diff options
author | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-01-17 01:30:42 +0000 |
---|---|---|
committer | Richard Smith <richard-llvm@metafoo.co.uk> | 2013-01-17 01:30:42 +0000 |
commit | cd8ab51a44e80625d84126780b0d85a7732e25af (patch) | |
tree | eb8a9f189b8553a98c361192ddb816b8f1703d5c /lib/Sema | |
parent | 6c3af3d0e3e65bcbca57bfd458d684941f6d0531 (diff) |
Implement C++11 semantics for [[noreturn]] attribute. This required splitting
it apart from [[gnu::noreturn]] / __attribute__((noreturn)), since their
semantics are not equivalent (for instance, we treat [[gnu::noreturn]] as
affecting the function type, whereas [[noreturn]] does not).
git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@172691 91177308-0d34-0410-b5e6-96231b3b80d8
Diffstat (limited to 'lib/Sema')
-rw-r--r-- | lib/Sema/AnalysisBasedWarnings.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaDecl.cpp | 12 | ||||
-rw-r--r-- | lib/Sema/SemaDeclAttr.cpp | 49 | ||||
-rw-r--r-- | lib/Sema/SemaStmt.cpp | 3 | ||||
-rw-r--r-- | lib/Sema/SemaType.cpp | 47 |
5 files changed, 84 insertions, 30 deletions
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: |