Index: include/clang/Basic/DiagnosticSemaKinds.td =================================================================== --- include/clang/Basic/DiagnosticSemaKinds.td +++ include/clang/Basic/DiagnosticSemaKinds.td @@ -6984,6 +6984,11 @@ def err_filter_expression_integral : Error< "filter expression type should be an integral value not %0">; +def err_non_asm_stmt_in_naked_function : Error< + "non-ASM statement in naked function is not supported">; +def err_asm_naked_parm_ref : Error< + "parameter references not allowed in naked functions">; + // OpenCL warnings and errors. def err_invalid_astype_of_different_size : Error< "invalid reinterpretation: sizes of %0 and %1 must match">; Index: lib/CodeGen/CGCall.cpp =================================================================== --- lib/CodeGen/CGCall.cpp +++ lib/CodeGen/CGCall.cpp @@ -1462,6 +1462,10 @@ void CodeGenFunction::EmitFunctionProlog(const CGFunctionInfo &FI, llvm::Function *Fn, const FunctionArgList &Args) { + if (CurCodeDecl && CurCodeDecl->hasAttr()) + // Naked functions don't have prologues. + return; + // If this is an implicit-return-zero function, go ahead and // initialize the return value. TODO: it might be nice to have // a more general mechanism for this that didn't require synthesized @@ -1985,6 +1989,12 @@ void CodeGenFunction::EmitFunctionEpilog(const CGFunctionInfo &FI, bool EmitRetDbgLoc, SourceLocation EndLoc) { + if (CurCodeDecl && CurCodeDecl->hasAttr()) { + // Naked functions don't have epilogues. + Builder.CreateUnreachable(); + return; + } + // Functions with no result always return void. if (!ReturnValue) { Builder.CreateRetVoid(); Index: lib/Sema/SemaDecl.cpp =================================================================== --- lib/Sema/SemaDecl.cpp +++ lib/Sema/SemaDecl.cpp @@ -10376,6 +10376,17 @@ !CheckConstexprFunctionBody(FD, Body))) FD->setInvalidDecl(); + if (FD && FD->hasAttr()) { + for (const Stmt *S : Body->children()) { + if (!isa(S)) { + Diag(S->getLocStart(), diag::err_non_asm_stmt_in_naked_function); + Diag(FD->getAttr()->getLocation(), diag::note_attribute); + FD->setInvalidDecl(); + break; + } + } + } + assert(ExprCleanupObjects.empty() && "Leftover temporaries in function"); assert(!ExprNeedsCleanups && "Unaccounted cleanups in function"); assert(MaybeODRUseExprs.empty() && Index: lib/Sema/SemaStmtAsm.cpp =================================================================== --- lib/Sema/SemaStmtAsm.cpp +++ lib/Sema/SemaStmtAsm.cpp @@ -405,6 +405,18 @@ Result = CheckPlaceholderExpr(Result.get()); if (!Result.isUsable()) return Result; + // Referring to parameters is not allowed in naked functions. + if (DeclRefExpr *DRE = dyn_cast(Result.get())) { + if (ParmVarDecl *Parm = dyn_cast(DRE->getDecl())) { + if (FunctionDecl *Func = dyn_cast(Parm->getDeclContext())) { + if (Func->hasAttr()) { + Diag(Id.getLocStart(), diag::err_asm_naked_parm_ref); + Diag(Func->getAttr()->getLocation(), diag::note_attribute); + } + } + } + } + QualType T = Result.get()->getType(); // For now, reject dependent types. Index: test/CodeGen/attr-naked.c =================================================================== --- test/CodeGen/attr-naked.c +++ test/CodeGen/attr-naked.c @@ -12,7 +12,16 @@ // Make sure this doesn't explode in the verifier. // (It doesn't really make sense, but it isn't invalid.) // CHECK: define void @t2() [[NAKED]] { -__attribute((naked, always_inline)) void t2() { +__attribute((naked, always_inline)) void t2() { +} + +// Make sure not to generate prolog or epilog for naked functions. +__attribute((naked)) void t3(int x) { +// CHECK: define void @t3(i32) +// CHECK-NEXT: entry +// CHECK-NOT: alloca +// CHECK-NOT: store +// CHECK-NEXT: unreachable } // CHECK: attributes [[NAKED]] = { naked noinline nounwind{{.*}} } Index: test/Sema/attr-naked.c =================================================================== --- test/Sema/attr-naked.c +++ test/Sema/attr-naked.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 %s -verify -fsyntax-only +// RUN: %clang_cc1 %s -verify -fsyntax-only -triple i686-pc-linux int a __attribute__((naked)); // expected-warning {{'naked' attribute only applies to functions}} @@ -10,3 +10,16 @@ void t2() __attribute__((naked(2))); // expected-error {{'naked' attribute takes no arguments}} +__attribute__((naked)) int t3() { // expected-note{{attribute is here}} + return 42; // expected-error{{non-ASM statement in naked function is not supported}} +} + +__attribute__((naked)) int t4() { + asm("movl $42, %eax"); + asm("retl"); +} + +__attribute__((naked)) int t5(int x) { + asm("movl x, %eax"); + asm("retl"); +} Index: test/Sema/ms-inline-asm.c =================================================================== --- test/Sema/ms-inline-asm.c +++ test/Sema/ms-inline-asm.c @@ -103,3 +103,14 @@ void test_operand_size() { __asm { call word t4 } // expected-error {{Expected 'PTR' or 'ptr' token!}} } + +__declspec(naked) int t5(int x) { // expected-note {{attribute is here}} + asm { movl eax, x } // expected-error {{parameter references not allowed in naked functions}} + asm { retl } +} + +int y; +__declspec(naked) int t6(int x) { + asm { mov eax, y } // No error. + asm { ret } +}