From 7586a6e6b7d79d4be031d2d0d6a35d5996cd0db9 Mon Sep 17 00:00:00 2001 From: Richard Smith Date: Wed, 30 Jan 2013 05:45:05 +0000 Subject: [PATCH] Semantic analysis and CodeGen support for C11's _Noreturn. This is modeled as an attribute for consistency with our other noreturn mechanisms. git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@173898 91177308-0d34-0410-b5e6-96231b3b80d8 --- include/clang/Basic/Attr.td | 6 ++++++ lib/AST/Decl.cpp | 1 + lib/CodeGen/CGCall.cpp | 14 ++++++-------- lib/Sema/SemaDecl.cpp | 10 ++++++++++ test/CodeGen/function-attributes.c | 8 +++++++- test/Sema/return-noreturn.c | 4 ++-- 6 files changed, 32 insertions(+), 11 deletions(-) diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 786b43a77b..52ebbb41db 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -303,6 +303,12 @@ def CUDAShared : InheritableAttr { let Spellings = [GNU<"shared">]; } +def C11NoReturn : InheritableAttr { + let Spellings = [Keyword<"_Noreturn">]; + let Subjects = [Function]; + let SemaHandler = 0; +} + def CXX11NoReturn : InheritableAttr { let Spellings = [CXX11<"","noreturn">, CXX11<"std","noreturn">]; let Subjects = [Function]; diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index f9ad946109..ed2a0c36fd 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1812,6 +1812,7 @@ bool FunctionDecl::isGlobal() const { bool FunctionDecl::isNoReturn() const { return hasAttr() || hasAttr() || + hasAttr() || getType()->getAs()->getNoReturnAttr(); } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index c29230f75b..e7b543a78c 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -983,19 +983,17 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, FuncAttrs.addAttribute(llvm::Attribute::ReturnsTwice); if (TargetDecl->hasAttr()) FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); - else if (const FunctionDecl *Fn = dyn_cast(TargetDecl)) { + if (TargetDecl->hasAttr()) + FuncAttrs.addAttribute(llvm::Attribute::NoReturn); + + if (const FunctionDecl *Fn = dyn_cast(TargetDecl)) { const FunctionProtoType *FPT = Fn->getType()->getAs(); if (FPT && FPT->isNothrow(getContext())) FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); + if (Fn->isNoReturn()) + FuncAttrs.addAttribute(llvm::Attribute::NoReturn); } - if (TargetDecl->hasAttr() || - TargetDecl->hasAttr()) - FuncAttrs.addAttribute(llvm::Attribute::NoReturn); - - if (TargetDecl->hasAttr()) - FuncAttrs.addAttribute(llvm::Attribute::ReturnsTwice); - // 'const' and 'pure' attribute functions are also nounwind. if (TargetDecl->hasAttr()) { FuncAttrs.addAttribute(llvm::Attribute::ReadNone); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 2c09c88b20..c94bf5f092 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -1900,6 +1900,11 @@ static void checkNewAttributesAfterDef(Sema &S, Decl *New, const Decl *Old) { ++I; continue; // regular attr merging will take care of validating this. } + // C's _Noreturn is allowed to be added to a function after it is defined. + if (isa(NewAttribute)) { + ++I; + continue; + } S.Diag(NewAttribute->getLocation(), diag::warn_attribute_precede_definition); S.Diag(Def->getLocation(), diag::note_previous_definition); @@ -5889,6 +5894,11 @@ Sema::ActOnFunctionDeclarator(Scope *S, Declarator &D, DeclContext *DC, NewFD->setDeclsInPrototypeScope(DeclsInPrototypeScope); DeclsInPrototypeScope.clear(); + if (D.getDeclSpec().isNoreturnSpecified()) + NewFD->addAttr( + ::new(Context) C11NoReturnAttr(D.getDeclSpec().getNoreturnSpecLoc(), + Context)); + // Process the non-inheritable attributes on this declaration. ProcessDeclAttributes(S, NewFD, D, /*NonInheritable=*/true, /*Inheritable=*/false); diff --git a/test/CodeGen/function-attributes.c b/test/CodeGen/function-attributes.c index 6cbf40ba22..886bd8d2fb 100644 --- a/test/CodeGen/function-attributes.c +++ b/test/CodeGen/function-attributes.c @@ -32,10 +32,16 @@ void __attribute__((always_inline)) f8(void) { } // CHECK: call void @f9_t() // CHECK: noreturn -// CHECK: { +// CHECK: } void __attribute__((noreturn)) f9_t(void); void f9(void) { f9_t(); } +// CHECK: call void @f9a() +// CHECK: noreturn +// CHECK: } +_Noreturn void f9a(void); +void f9b(void) { f9a(); } + // FIXME: We should be setting nounwind on calls. // CHECK: call i32 @f10_t() // CHECK: readnone diff --git a/test/Sema/return-noreturn.c b/test/Sema/return-noreturn.c index 5dd6693373..6d521eb017 100644 --- a/test/Sema/return-noreturn.c +++ b/test/Sema/return-noreturn.c @@ -36,7 +36,7 @@ test4() { test2_positive(); } -// FIXME: do not warn here. -_Noreturn void test5() { // expected-warning {{could be declared with attribute 'noreturn'}} +// Do not warn here. +_Noreturn void test5() { test2_positive(); } -- 2.40.0