diff options
Diffstat (limited to 'lib')
-rw-r--r-- | lib/AST/Decl.cpp | 5 | ||||
-rw-r--r-- | lib/Analysis/CFG.cpp | 12 | ||||
-rw-r--r-- | lib/CodeGen/CGCall.cpp | 3 | ||||
-rw-r--r-- | lib/Parse/ParseDecl.cpp | 2 | ||||
-rw-r--r-- | lib/Parse/ParseDeclCXX.cpp | 9 | ||||
-rw-r--r-- | lib/Parse/Parser.cpp | 3 | ||||
-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 | ||||
-rw-r--r-- | lib/StaticAnalyzer/Checkers/NoReturnFunctionChecker.cpp | 2 |
12 files changed, 109 insertions, 41 deletions
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. |