diff options
24 files changed, 200 insertions, 53 deletions
diff --git a/include/clang/AST/Decl.h b/include/clang/AST/Decl.h index bb0794ed04..3cca66f068 100644 --- a/include/clang/AST/Decl.h +++ b/include/clang/AST/Decl.h @@ -1799,6 +1799,10 @@ public: /// \brief Determines whether this is a global function. bool isGlobal() const; + /// \brief Determines whether this function is known to be 'noreturn', through + /// an attribute on its declaration or its type. + bool isNoReturn() const; + /// \brief True if the function was a definition but its body was skipped. bool hasSkippedBody() const { return HasSkippedBody; } void setHasSkippedBody(bool Skipped = true) { HasSkippedBody = Skipped; } diff --git a/include/clang/AST/Type.h b/include/clang/AST/Type.h index 2f1b48eb0f..f1db761557 100644 --- a/include/clang/AST/Type.h +++ b/include/clang/AST/Type.h @@ -2706,6 +2706,9 @@ public: bool getHasRegParm() const { return getExtInfo().getHasRegParm(); } unsigned getRegParmType() const { return getExtInfo().getRegParm(); } + /// \brief Determine whether this function type includes the GNU noreturn + /// attribute. The C++11 [[noreturn]] attribute does not affect the function + /// type. bool getNoReturnAttr() const { return getExtInfo().getNoReturn(); } CallingConv getCallConv() const { return getExtInfo().getCC(); } ExtInfo getExtInfo() const { return ExtInfo(FunctionTypeBits.ExtInfo); } diff --git a/include/clang/Basic/Attr.td b/include/clang/Basic/Attr.td index 9dd92ad2ee..2d4788ce2b 100644 --- a/include/clang/Basic/Attr.td +++ b/include/clang/Basic/Attr.td @@ -296,6 +296,11 @@ def CUDAShared : InheritableAttr { let Spellings = [GNU<"shared">]; } +def CXX11NoReturn : InheritableAttr { + let Spellings = [CXX11<"","noreturn">, CXX11<"std","noreturn">]; + let Subjects = [Function]; +} + def OpenCLKernel : Attr { let Spellings = [GNU<"opencl_kernel_function">]; } @@ -466,8 +471,7 @@ def NonNull : InheritableAttr { } def NoReturn : InheritableAttr { - let Spellings = [GNU<"noreturn">, CXX11<"gnu", "noreturn">, - CXX11<"", "noreturn">, CXX11<"std", "noreturn">]; + let Spellings = [GNU<"noreturn">, CXX11<"gnu", "noreturn">]; // FIXME: Does GCC allow this on the function instead? let Subjects = [Function]; } diff --git a/include/clang/Basic/DiagnosticParseKinds.td b/include/clang/Basic/DiagnosticParseKinds.td index f218bb7dce..963263bebd 100644 --- a/include/clang/Basic/DiagnosticParseKinds.td +++ b/include/clang/Basic/DiagnosticParseKinds.td @@ -501,6 +501,8 @@ def err_cxx11_attribute_forbids_arguments : Error< "attribute '%0' cannot have an argument list">; def err_cxx11_attribute_forbids_ellipsis : Error< "attribute '%0' cannot be used as an attribute pack">; +def err_cxx11_attribute_repeated : Error< + "attribute %0 cannot appear multiple times in an attribute specifier">; def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; def err_l_square_l_square_not_attribute : Error< "C++11 only allows consecutive left square brackets when " diff --git a/include/clang/Basic/DiagnosticSemaKinds.td b/include/clang/Basic/DiagnosticSemaKinds.td index 89aa73f47b..ae88e9ea45 100644 --- a/include/clang/Basic/DiagnosticSemaKinds.td +++ b/include/clang/Basic/DiagnosticSemaKinds.td @@ -1830,6 +1830,8 @@ def err_attribute_wrong_decl_type : Error< "functions, methods, and parameters|classes|variables|methods|" "variables, functions and labels|fields and global variables|structs|" "variables, functions and tag types|thread-local variables}1">; +def err_attribute_not_type_attr : Error< + "'%0' attribute cannot be applied to types">; def warn_function_attribute_wrong_type : Warning< "'%0' only applies to function types; type here is %1">, InGroup<IgnoredAttributes>; @@ -5861,6 +5863,10 @@ def warn_falloff_noreturn_function : Warning< InGroup<InvalidNoreturn>; def err_noreturn_block_has_return_expr : Error< "block declared 'noreturn' should not return">; +def err_noreturn_missing_on_first_decl : Error< + "function declared '[[noreturn]]' after its first declaration">; +def note_noreturn_missing_first_decl : Note< + "declaration missing '[[noreturn]]' attribute is here">; def err_block_on_nonlocal : Error< "__block attribute not allowed, only allowed on local variables">; def err_block_on_vm : Error< diff --git a/include/clang/Sema/Sema.h b/include/clang/Sema/Sema.h index 06bd6744f5..20fe22b440 100644 --- a/include/clang/Sema/Sema.h +++ b/include/clang/Sema/Sema.h @@ -2323,9 +2323,12 @@ public: // Decl attributes - this routine is the top level dispatcher. void ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, - bool NonInheritable = true, bool Inheritable = true); + bool NonInheritable = true, + bool Inheritable = true); void ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AL, - bool NonInheritable = true, bool Inheritable = true); + bool NonInheritable = true, + bool Inheritable = true, + bool IncludeCXX11Attributes = true); bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, const AttributeList *AttrList); diff --git a/lib/AST/Decl.cpp b/lib/AST/Decl.cpp index 103ac1bd4a..c053b6d17e 100644 --- a/lib/AST/Decl.cpp +++ b/lib/AST/Decl.cpp @@ -1808,6 +1808,11 @@ bool FunctionDecl::isGlobal() const { return true; } +bool FunctionDecl::isNoReturn() const { + return hasAttr<NoReturnAttr>() || hasAttr<CXX11NoReturnAttr>() || + getType()->getAs<FunctionType>()->getNoReturnAttr(); +} + void FunctionDecl::setPreviousDeclaration(FunctionDecl *PrevDecl) { redeclarable_base::setPreviousDeclaration(PrevDecl); diff --git a/lib/Analysis/CFG.cpp b/lib/Analysis/CFG.cpp index 043066bd60..cd0ff0a492 100644 --- a/lib/Analysis/CFG.cpp +++ b/lib/Analysis/CFG.cpp @@ -807,7 +807,7 @@ void CFGBuilder::addAutomaticObjDtors(LocalScope::const_iterator B, Ty = Context->getBaseElementType(Ty); const CXXDestructorDecl *Dtor = Ty->getAsCXXRecordDecl()->getDestructor(); - if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr()) + if (Dtor->isNoReturn()) Block = createNoReturnBlock(); else autoCreateBlock(); @@ -1402,7 +1402,7 @@ CFGBlock *CFGBuilder::VisitCallExpr(CallExpr *C, AddStmtChoice asc) { } if (FunctionDecl *FD = C->getDirectCallee()) { - if (FD->hasAttr<NoReturnAttr>()) + if (FD->isNoReturn()) NoReturn = true; if (FD->hasAttr<NoThrowAttr>()) AddEHEdge = false; @@ -3190,7 +3190,7 @@ CFGBlock *CFGBuilder::VisitCXXBindTemporaryExprForTemporaryDtors( // a new block for the destructor which does not have as a successor // anything built thus far. Control won't flow out of this block. const CXXDestructorDecl *Dtor = E->getTemporary()->getDestructor(); - if (cast<FunctionType>(Dtor->getType())->getNoReturnAttr()) + if (Dtor->isNoReturn()) Block = createNoReturnBlock(); else autoCreateBlock(); @@ -3327,10 +3327,8 @@ CFGImplicitDtor::getDestructorDecl(ASTContext &astContext) const { } bool CFGImplicitDtor::isNoReturn(ASTContext &astContext) const { - if (const CXXDestructorDecl *decl = getDestructorDecl(astContext)) { - QualType ty = decl->getType(); - return cast<FunctionType>(ty)->getNoReturnAttr(); - } + if (const CXXDestructorDecl *DD = getDestructorDecl(astContext)) + return DD->isNoReturn(); return false; } diff --git a/lib/CodeGen/CGCall.cpp b/lib/CodeGen/CGCall.cpp index 878b73d39c..d9a00453df 100644 --- a/lib/CodeGen/CGCall.cpp +++ b/lib/CodeGen/CGCall.cpp @@ -989,7 +989,8 @@ void CodeGenModule::ConstructAttributeList(const CGFunctionInfo &FI, FuncAttrs.addAttribute(llvm::Attribute::NoUnwind); } - if (TargetDecl->hasAttr<NoReturnAttr>()) + if (TargetDecl->hasAttr<NoReturnAttr>() || + TargetDecl->hasAttr<CXX11NoReturnAttr>()) FuncAttrs.addAttribute(llvm::Attribute::NoReturn); if (TargetDecl->hasAttr<ReturnsTwiceAttr>()) diff --git a/lib/Parse/ParseDecl.cpp b/lib/Parse/ParseDecl.cpp index 1fbe6b3a1a..74769bf731 100644 --- a/lib/Parse/ParseDecl.cpp +++ b/lib/Parse/ParseDecl.cpp @@ -902,6 +902,8 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA, ConsumeAnyToken(); if (OnDefinition && !IsThreadSafetyAttribute(LA.AttrName.getName())) { + // FIXME: Do not warn on C++11 attributes, once we start supporting + // them here. Diag(Tok, diag::warn_attribute_on_function_definition) << LA.AttrName.getName(); } diff --git a/lib/Parse/ParseDeclCXX.cpp b/lib/Parse/ParseDeclCXX.cpp index 7fe49fd995..d78cc51a77 100644 --- a/lib/Parse/ParseDeclCXX.cpp +++ b/lib/Parse/ParseDeclCXX.cpp @@ -3032,7 +3032,7 @@ static bool IsBuiltInOrStandardCXX11Attribute(IdentifierInfo *AttrName, AttributeList::AS_CXX11)) { case AttributeList::AT_CarriesDependency: case AttributeList::AT_FallThrough: - case AttributeList::AT_NoReturn: { + case AttributeList::AT_CXX11NoReturn: { return true; } @@ -3095,6 +3095,8 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, ConsumeBracket(); ConsumeBracket(); + llvm::SmallDenseMap<IdentifierInfo*, SourceLocation, 4> SeenAttrs; + while (Tok.isNot(tok::r_square)) { // attribute not present if (Tok.is(tok::comma)) { @@ -3128,6 +3130,11 @@ void Parser::ParseCXX11AttributeSpecifier(ParsedAttributes &attrs, bool StandardAttr = IsBuiltInOrStandardCXX11Attribute(AttrName,ScopeName); bool AttrParsed = false; + if (StandardAttr && + !SeenAttrs.insert(std::make_pair(AttrName, AttrLoc)).second) + Diag(AttrLoc, diag::err_cxx11_attribute_repeated) + << AttrName << SourceRange(SeenAttrs[AttrName]); + // Parse attribute arguments if (Tok.is(tok::l_paren)) { if (ScopeName && ScopeName->getName() == "gnu") { diff --git a/lib/Parse/Parser.cpp b/lib/Parse/Parser.cpp index 759ab7f60c..20e515d102 100644 --- a/lib/Parse/Parser.cpp +++ b/lib/Parse/Parser.cpp @@ -944,7 +944,8 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D, if (Tok.isNot(tok::equal)) { AttributeList *DtorAttrs = D.getAttributes(); while (DtorAttrs) { - if (!IsThreadSafetyAttribute(DtorAttrs->getName()->getName())) { + if (!IsThreadSafetyAttribute(DtorAttrs->getName()->getName()) && + !DtorAttrs->isCXX11Attribute()) { Diag(DtorAttrs->getLoc(), diag::warn_attribute_on_function_definition) << DtorAttrs->getName()->getName(); } diff --git a/lib/Sema/AnalysisBasedWarnings.cpp b/lib/Sema/AnalysisBasedWarnings.cpp index ba23467931..d5fa959bf4 100644 --- a/lib/Sema/AnalysisBasedWarnings.cpp +++ b/lib/Sema/AnalysisBasedWarnings.cpp @@ -329,8 +329,7 @@ static void CheckFallThroughForBody(Sema &S, const Decl *D, const Stmt *Body, if (const FunctionDecl *FD = dyn_cast<FunctionDecl>(D)) { ReturnsVoid = FD->getResultType()->isVoidType(); - HasNoReturn = FD->hasAttr<NoReturnAttr>() || - FD->getType()->getAs<FunctionType>()->getNoReturnAttr(); + HasNoReturn = FD->isNoReturn(); } else if (const ObjCMethodDecl *MD = dyn_cast<ObjCMethodDecl>(D)) { ReturnsVoid = MD->getResultType()->isVoidType(); diff --git a/lib/Sema/SemaDecl.cpp b/lib/Sema/SemaDecl.cpp index 5ddc26ab25..728a58ee61 100644 --- a/lib/Sema/SemaDecl.cpp +++ b/lib/Sema/SemaDecl.cpp @@ -2276,6 +2276,18 @@ bool Sema::MergeFunctionDecl(FunctionDecl *New, Decl *OldD, Scope *S) { } } + // C++11 [dcl.attr.noreturn]p1: + // The first declaration of a function shall specify the noreturn + // attribute if any declaration of that function specifies the noreturn + // attribute. + if (New->hasAttr<CXX11NoReturnAttr>() && + !Old->hasAttr<CXX11NoReturnAttr>()) { + Diag(New->getAttr<CXX11NoReturnAttr>()->getLocation(), + diag::err_noreturn_missing_on_first_decl); + Diag(Old->getFirstDeclaration()->getLocation(), + diag::note_noreturn_missing_first_decl); + } + // (C++98 8.3.5p3): // All declarations for a function shall agree exactly in both the // return type and the parameter-type-list. diff --git a/lib/Sema/SemaDeclAttr.cpp b/lib/Sema/SemaDeclAttr.cpp index acd075ee7f..45220f60d3 100644 --- a/lib/Sema/SemaDeclAttr.cpp +++ b/lib/Sema/SemaDeclAttr.cpp @@ -1684,6 +1684,21 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, D->addAttr(::new (S.Context) AnalyzerNoReturnAttr(Attr.getRange(), S.Context)); } +static void handleCXX11NoReturnAttr(Sema &S, Decl *D, + const AttributeList &Attr) { + // C++11 [dcl.attr.noreturn]p1: + // The attribute may be applied to the declarator-id in a function + // declaration. + FunctionDecl *FD = dyn_cast<FunctionDecl>(D); + if (!FD) { + S.Diag(Attr.getLoc(), diag::err_attribute_wrong_decl_type) + << Attr.getName() << ExpectedFunctionOrMethod; + return; + } + + D->addAttr(::new (S.Context) CXX11NoReturnAttr(Attr.getRange(), S.Context)); +} + // PS3 PPU-specific. static void handleVecReturnAttr(Sema &S, Decl *D, const AttributeList &Attr) { /* @@ -4272,10 +4287,10 @@ static void ProcessNonInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, const AttributeList &Attr) { switch (Attr.getKind()) { - case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break; - case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break; - case AttributeList::AT_IBOutletCollection: - handleIBOutletCollection(S, D, Attr); break; + case AttributeList::AT_IBAction: handleIBAction(S, D, Attr); break; + case AttributeList::AT_IBOutlet: handleIBOutlet(S, D, Attr); break; + case AttributeList::AT_IBOutletCollection: + handleIBOutletCollection(S, D, Attr); break; case AttributeList::AT_AddressSpace: case AttributeList::AT_OpenCLImageAccess: case AttributeList::AT_ObjCGC: @@ -4306,6 +4321,9 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, case AttributeList::AT_Common: handleCommonAttr (S, D, Attr); break; case AttributeList::AT_CUDAConstant:handleConstantAttr (S, D, Attr); break; case AttributeList::AT_Constructor: handleConstructorAttr (S, D, Attr); break; + case AttributeList::AT_CXX11NoReturn: + handleCXX11NoReturnAttr(S, D, Attr); + break; case AttributeList::AT_Deprecated: handleAttrWithMessage<DeprecatedAttr>(S, D, Attr, "deprecated"); break; @@ -4542,11 +4560,11 @@ static void ProcessInheritableDeclAttr(Sema &S, Scope *scope, Decl *D, /// ProcessDeclAttribute - Apply the specific attribute to the specified decl if /// the attribute applies to decls. If the attribute is a type attribute, just -/// silently ignore it if a GNU attribute. FIXME: Applying a C++0x attribute to -/// the wrong thing is illegal (C++0x [dcl.attr.grammar]/4). +/// silently ignore it if a GNU attribute. static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const AttributeList &Attr, - bool NonInheritable, bool Inheritable) { + bool NonInheritable, bool Inheritable, + bool IncludeCXX11Attributes) { if (Attr.isInvalid()) return; @@ -4557,6 +4575,11 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, if (Attr.isMSTypespecAttribute()) return; + // Ignore C++11 attributes on declarator chunks: they appertain to the type + // instead. + if (Attr.isCXX11Attribute() && !IncludeCXX11Attributes) + return; + if (NonInheritable) ProcessNonInheritableDeclAttr(S, scope, D, Attr); @@ -4568,10 +4591,11 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, /// attribute list to the specified decl, ignoring any type attributes. void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, const AttributeList *AttrList, - bool NonInheritable, bool Inheritable) { - for (const AttributeList* l = AttrList; l; l = l->getNext()) { - ProcessDeclAttribute(*this, S, D, *l, NonInheritable, Inheritable); - } + bool NonInheritable, bool Inheritable, + bool IncludeCXX11Attributes) { + for (const AttributeList* l = AttrList; l; l = l->getNext()) + ProcessDeclAttribute(*this, S, D, *l, NonInheritable, Inheritable, + IncludeCXX11Attributes); // GCC accepts // static int a9 __attribute__((weakref)); @@ -4736,7 +4760,8 @@ void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD, // when X is a decl attribute. for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) if (const AttributeList *Attrs = PD.getTypeObject(i).getAttrs()) - ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable); + ProcessDeclAttributeList(S, D, Attrs, NonInheritable, Inheritable, + /*IncludeCXX11Attributes=*/false); // Finally, apply any attributes on the decl itself. if (const AttributeList *Attrs = PD.getAttributes()) diff --git a/lib/Sema/SemaStmt.cpp b/lib/Sema/SemaStmt.cpp index 09c418072d..db314fa50c 100644 --- a/lib/Sema/SemaStmt.cpp +++ b/lib/Sema/SemaStmt.cpp @@ -2419,8 +2419,7 @@ Sema::ActOnReturnStmt(SourceLocation ReturnLoc, Expr *RetValExp) { QualType RelatedRetType; if (const FunctionDecl *FD = getCurFunctionDecl()) { FnRetType = FD->getResultType(); - if (FD->hasAttr<NoReturnAttr>() || - FD->getType()->getAs<FunctionType>()->getNoReturnAttr()) + if (FD->isNoReturn()) Diag(ReturnLoc, diag::warn_noreturn_function_has_return_expr) << FD->getDeclName(); } else if (ObjCMethodDecl *MD = getCurMethodDecl()) { diff --git a/lib/Sema/SemaType.cpp b/lib/Sema/SemaType.cpp index e849e05c7b..702954322e 100644 --- a/lib/Sema/SemaType.cpp +++ b/lib/Sema/SemaType.cpp @@ -4189,24 +4189,43 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, if (attr.isInvalid()) continue; - // [[gnu::...]] attributes are treated as declaration attributes, so may - // not appertain to a DeclaratorChunk, even if we handle them as type - // attributes. - // FIXME: All other C++11 type attributes may *only* appertain to a type, - // and should only be considered here if they appertain to a - // DeclaratorChunk. - if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk && - attr.getScopeName() && attr.getScopeName()->isStr("gnu")) { - state.getSema().Diag(attr.getLoc(), - diag::warn_cxx11_gnu_attribute_on_type) - << attr.getName(); - continue; + if (attr.isCXX11Attribute()) { + // [[gnu::...]] attributes are treated as declaration attributes, so may + // not appertain to a DeclaratorChunk, even if we handle them as type + // attributes. + if (attr.getScopeName() && attr.getScopeName()->isStr("gnu")) { + if (TAL == TAL_DeclChunk) { + state.getSema().Diag(attr.getLoc(), + diag::warn_cxx11_gnu_attribute_on_type) + << attr.getName(); + continue; + } + } else if (TAL != TAL_DeclChunk) { + // Otherwise, only consider type processing for a C++11 attribute if + // it's actually been applied to a type. + continue; + } } // If this is an attribute we can handle, do so now, // otherwise, add it to the FnAttrs list for rechaining. switch (attr.getKind()) { - default: break; + default: + // A C++11 attribute on a declarator chunk must appertain to a type. + if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk) + state.getSema().Diag(attr.getLoc(), diag::err_attribute_not_type_attr) + << attr.getName()->getName(); + break; + + case AttributeList::UnknownAttribute: + if (attr.isCXX11Attribute() && TAL == TAL_DeclChunk) + state.getSema().Diag(attr.getLoc(), + diag::warn_unknown_attribute_ignored) + << attr.getName(); + break; + + case AttributeList::IgnoredAttribute: + break; case AttributeList::AT_MayAlias: // FIXME: This attribute needs to actually be handled, but if we ignore @@ -4255,7 +4274,7 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, case AttributeList::AT_NSReturnsRetained: if (!state.getSema().getLangOpts().ObjCAutoRefCount) - break; + break; // fallthrough into the function attrs FUNCTION_TYPE_ATTRS_CASELIST: diff --git a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp index 2439147aff..37d91138f0 100644 --- a/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp +++ b/lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp @@ -48,7 +48,7 @@ void NoReturnFunctionChecker::checkPostStmt(const CallExpr *CE, if (!FD) return; - if (FD->getAttr<AnalyzerNoReturnAttr>()) + if (FD->getAttr<AnalyzerNoReturnAttr>() || FD->isNoReturn()) BuildSinks = true; else if (const IdentifierInfo *II = FD->getIdentifier()) { // HACK: Some functions are not marked noreturn, and don't return. diff --git a/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp new file mode 100644 index 0000000000..0af241f55f --- /dev/null +++ b/test/CXX/dcl.dcl/dcl.attr/dcl.attr.noreturn/p1.cpp @@ -0,0 +1,44 @@ +// RUN: %clang_cc1 -std=c++11 -verify -fcxx-exceptions %s + +[[noreturn]] void a() { + return; // expected-warning {{function 'a' declared 'noreturn' should not return}} +} +void a2 [[noreturn]] () { + return; // expected-warning {{function 'a2' declared 'noreturn' should not return}} +} + +[[noreturn, noreturn]] void b() { throw 0; } // expected-error {{attribute 'noreturn' cannot appear multiple times in an attribute specifier}} +[[noreturn]] [[noreturn]] void b2() { throw 0; } // ok + +[[noreturn()]] void c(); // expected-error {{attribute 'noreturn' cannot have an argument list}} + +void d() [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to types}} +int d2 [[noreturn]]; // expected-error {{'noreturn' attribute only applies to functions and methods}} + +[[noreturn]] int e() { b2(); } // ok + +int f(); // expected-note {{declaration missing '[[noreturn]]' attribute is here}} +[[noreturn]] int f(); // expected-error {{function declared '[[noreturn]]' after its first declaration}} +int f(); + +[[noreturn]] int g(); +int g() { while (true) b(); } // ok +[[noreturn]] int g(); + +[[gnu::noreturn]] int h(); + +template<typename T> void test_type(T) { T::error; } // expected-error {{has no members}} +template<> void test_type(int (*)()) {} + +void check() { + // We do not consider [[noreturn]] to be part of the function's type. + // However, we do treat [[gnu::noreturn]] as being part of the type. + // + // This isn't quite GCC-compatible; it treats [[gnu::noreturn]] as + // being part of a function *pointer* type, but not being part of + // a function type. + test_type(e); + test_type(f); + test_type(g); + test_type(h); // expected-note {{instantiation}} +} diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp index 68460f0354..9dffc1ff26 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/p5.cpp @@ -5,7 +5,8 @@ void test_attributes() { auto nrl = [](int x) -> int { if (x > 0) return x; }; // expected-warning{{control may reach end of non-void lambda}} - auto nrl2 = []() [[noreturn]] { return; }; // expected-error{{lambda declared 'noreturn' should not return}} + // FIXME: GCC accepts the [[gnu::noreturn]] attribute here. + auto nrl2 = []() [[gnu::noreturn]] { return; }; // expected-warning{{attribute 'noreturn' ignored}} } template<typename T> diff --git a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp index 49b9c66b1c..407b083231 100644 --- a/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp +++ b/test/CXX/expr/expr.prim/expr.prim.lambda/templates.cpp @@ -2,10 +2,11 @@ template<typename T> void test_attributes() { - auto nrl = []() [[noreturn]] {}; // expected-error{{lambda declared 'noreturn' should not return}} + // FIXME: GCC accepts [[gnu::noreturn]] here. + auto nrl = []() [[gnu::noreturn]] {}; // expected-warning{{attribute 'noreturn' ignored}} } -template void test_attributes<int>(); // expected-note{{in instantiation of function}} +template void test_attributes<int>(); template<typename T> void call_with_zero() { diff --git a/test/CodeGenCXX/cxx11-noreturn.cpp b/test/CodeGenCXX/cxx11-noreturn.cpp new file mode 100644 index 0000000000..ee513120f9 --- /dev/null +++ b/test/CodeGenCXX/cxx11-noreturn.cpp @@ -0,0 +1,8 @@ +// RUN: %clang_cc1 -emit-llvm -std=c++11 %s -o - | FileCheck %s + +int g(); + +// CHECK: _Z1fv(){{.*}} noreturn +[[noreturn]] int f() { + while (g()) {} +} diff --git a/test/Parser/cxx0x-attributes.cpp b/test/Parser/cxx0x-attributes.cpp index dac159a03f..ab6aa70c28 100644 --- a/test/Parser/cxx0x-attributes.cpp +++ b/test/Parser/cxx0x-attributes.cpp @@ -210,8 +210,11 @@ template<typename...Ts> void variadic() { // Expression tests void bar () { - [] () [[noreturn]] { return; } (); // expected-error {{should not return}} - [] () [[noreturn]] { throw; } (); + // FIXME: GCC accepts [[gnu::noreturn]] on a lambda, even though it appertains + // to the operator()'s type, and GCC does not otherwise accept attributes + // applied to types. Use that to test this. + [] () [[gnu::noreturn]] { return; } (); // expected-warning {{attribute 'noreturn' ignored}} FIXME-error {{should not return}} + [] () [[gnu::noreturn]] { throw; } (); // expected-warning {{attribute 'noreturn' ignored}} new int[42][[]][5][[]]{}; } diff --git a/test/Parser/objcxx11-attributes.mm b/test/Parser/objcxx11-attributes.mm index 9ad85d310f..c72f26d101 100644 --- a/test/Parser/objcxx11-attributes.mm +++ b/test/Parser/objcxx11-attributes.mm @@ -13,12 +13,12 @@ void f(X *noreturn) { int a[ [noreturn getSize] ]; // ... but is interpreted as an attribute where possible. - int b[ [noreturn] ]; // expected-warning {{'noreturn' only applies to function types}} + int b[ [noreturn] ]; // expected-error {{'noreturn' attribute only applies to functions and methods}} int c[ [noreturn getSize] + 1 ]; // An array size which is computed by a lambda is not OK. - int d[ [noreturn] { return 3; } () ]; // expected-error {{expected ']'}} expected-warning {{'noreturn' only applies}} + int d[ [noreturn] { return 3; } () ]; // expected-error {{expected ']'}} expected-error {{'noreturn' attribute only applies}} // A message send which contains a message send is OK. [ [ X alloc ] init ]; @@ -40,7 +40,7 @@ void f(X *noreturn) { expected-warning {{unknown attribute 'bitand' ignored}} // FIXME: Suppress vexing parse warning - [[noreturn]]int(e)(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}} + [[gnu::noreturn]]int(e)(); // expected-warning {{function declaration}} expected-note {{replace parentheses with an initializer}} int e2(); // expected-warning {{interpreted as a function declaration}} expected-note{{}} // A function taking a noreturn function. |