diff --git a/clang/include/clang/Basic/AttributeCommonInfo.h b/clang/include/clang/Basic/AttributeCommonInfo.h --- a/clang/include/clang/Basic/AttributeCommonInfo.h +++ b/clang/include/clang/Basic/AttributeCommonInfo.h @@ -146,6 +146,7 @@ bool isMicrosoftAttribute() const { return SyntaxUsed == AS_Microsoft; } bool isGNUScope() const; + bool isClangScope() const; bool isAlignasAttribute() const { // FIXME: Use a better mechanism to determine this. diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3381,8 +3381,11 @@ "annotating the 'if %select{constexpr|consteval}0' statement here">; def err_decl_attribute_invalid_on_stmt : Error< "%0 attribute cannot be applied to a statement">; -def err_stmt_attribute_invalid_on_decl : Error< +def err_attribute_invalid_on_decl : Error< "%0 attribute cannot be applied to a declaration">; +def warn_type_attribute_deprecated_on_decl : Warning< + "applying attribute %0 to a declaration is deprecated; apply it to the type instead">, + InGroup; def warn_declspec_attribute_ignored : Warning< "attribute %0 is ignored, place it after " "\"%select{class|struct|interface|union|enum}1\" to apply attribute to " diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2066,7 +2066,8 @@ SourceLocation *TrailingElseLoc = nullptr); StmtResult ParseStatementOrDeclarationAfterAttributes( StmtVector &Stmts, ParsedStmtContext StmtCtx, - SourceLocation *TrailingElseLoc, ParsedAttributes &Attrs); + SourceLocation *TrailingElseLoc, ParsedAttributes &DeclAttrs, + ParsedAttributes &DeclSpecAttrs); StmtResult ParseExprStatement(ParsedStmtContext StmtCtx); StmtResult ParseLabeledStatement(ParsedAttributes &Attrs, ParsedStmtContext StmtCtx); @@ -2307,15 +2308,18 @@ DeclGroupPtrTy ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, - ParsedAttributes &Attrs, + ParsedAttributes &DeclAttrs, + ParsedAttributes &DeclSpecAttrs, SourceLocation *DeclSpecStart = nullptr); DeclGroupPtrTy ParseSimpleDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, - ParsedAttributes &Attrs, bool RequireSemi, + ParsedAttributes &DeclAttrs, + ParsedAttributes &DeclSpecAttrs, bool RequireSemi, ForRangeInit *FRI = nullptr, SourceLocation *DeclSpecStart = nullptr); bool MightBeDeclarator(DeclaratorContext Context); DeclGroupPtrTy ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context, + ParsedAttributes &Attrs, SourceLocation *DeclEnd = nullptr, ForRangeInit *FRI = nullptr); Decl *ParseDeclarationAfterDeclarator(Declarator &D, @@ -3015,7 +3019,8 @@ unsigned int index, SourceLocation &InlineLoc, ParsedAttributes &attrs, BalancedDelimiterTracker &Tracker); - Decl *ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context); + Decl *ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context, + ParsedAttributes &DeclAttrs); Decl *ParseExportDeclaration(); DeclGroupPtrTy ParseUsingDirectiveOrDeclaration( DeclaratorContext Context, const ParsedTemplateInfo &TemplateInfo, diff --git a/clang/include/clang/Parse/RAIIObjectsForParser.h b/clang/include/clang/Parse/RAIIObjectsForParser.h --- a/clang/include/clang/Parse/RAIIObjectsForParser.h +++ b/clang/include/clang/Parse/RAIIObjectsForParser.h @@ -213,8 +213,8 @@ return const_cast(getDeclSpec()); } - void clear() { - Declarator::clear(); + void clearExceptDeclarationAttrs() { + Declarator::clearExceptDeclarationAttrs(); ParsingRAII.reset(); } diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1853,6 +1853,8 @@ /// Attrs - Attributes. ParsedAttributes Attrs; + ParsedAttributes DeclarationAttrs; + /// The asm label, if specified. Expr *AsmLabel; @@ -1899,7 +1901,8 @@ Redeclaration(false), Extension(false), ObjCIvar(false), ObjCWeakProperty(false), InlineStorageUsed(false), HasInitializer(false), Attrs(ds.getAttributePool().getFactory()), - AsmLabel(nullptr), TrailingRequiresClause(nullptr), + DeclarationAttrs(ds.getAttributePool().getFactory()), AsmLabel(nullptr), + TrailingRequiresClause(nullptr), InventedTemplateParameterList(nullptr) {} ~Declarator() { @@ -1971,6 +1974,14 @@ /// Reset the contents of this Declarator. void clear() { + clearExceptDeclarationAttrs(); + DeclarationAttrs.clear(); + } + + /// Reset the contents of this Declarator, except for the declaration + /// attributes. The intent is that the declaration attributes can be reused + /// for multiple declarators in the same declaration. + void clearExceptDeclarationAttrs() { SS.clear(); Name.clear(); Range = DS.getSourceRange(); @@ -2520,12 +2531,31 @@ SetRangeEnd(attrs.Range.getEnd()); } + /// takeDeclarationAttributes - Takes attributes from the given + /// parsed-attributes set and associates them with the declaration (rather + /// than the declarator). + /// + /// Here is an example of an attribute associated with a declaration: + /// [[deprecated]] int x, y; + /// + /// This attribute appertains to all of the entities declared in the + /// declaration, i.e. `x` and `y` in this case. + void takeDeclarationAttributes(ParsedAttributes &attrs) { + DeclarationAttrs.takeAllFrom(attrs); + } + const ParsedAttributes &getAttributes() const { return Attrs; } ParsedAttributes &getAttributes() { return Attrs; } + const ParsedAttributes &getDeclarationAttributes() const { + return DeclarationAttrs; + } + ParsedAttributes &getDeclarationAttributes() { return DeclarationAttrs; } + /// hasAttributes - do we contain any attributes? bool hasAttributes() const { - if (!getAttributes().empty() || getDeclSpec().hasAttributes()) + if (!getAttributes().empty() || !getDeclarationAttributes().empty() || + getDeclSpec().hasAttributes()) return true; for (unsigned i = 0, e = getNumTypeObjects(); i != e; ++i) if (!getTypeObject(i).getAttrs().empty()) diff --git a/clang/include/clang/Sema/ParsedAttr.h b/clang/include/clang/Sema/ParsedAttr.h --- a/clang/include/clang/Sema/ParsedAttr.h +++ b/clang/include/clang/Sema/ParsedAttr.h @@ -651,6 +651,16 @@ bool isKnownToGCC() const; bool isSupportedByPragmaAttribute() const; + /// Returns whether the attribute, if specified ahead of a declaration, + /// should be applied to the decl-specifier-seq instead (i.e. whether it + /// "slides" to the decl-specifier-seq). + /// Attributes with GNU, __declspec or keyword syntax generally slide + /// to the decl-specifier-seq. C++11 attributes specified ahead of the + /// declaration always appertain to the declaration according to the standard, + /// but historically we have allowed some of these attributes to slide to + /// the decl-specifier-seq too, so we need to keep supporting this behavior. + bool slidesFromDeclToDeclSpec() const; + /// If the parsed attribute has a semantic equivalent, and it would /// have a semantic Spelling enumeration (due to having semantically-distinct /// spelling variations), return the value of that semantic spelling. If the @@ -1103,6 +1113,11 @@ mutable AttributePool pool; }; +/// Consumes the attributes from `First` and `Second` and concatenates them into +/// `Result`. Sets `Result.Range` to the combined range of `First` and `Second`. +void ConcatenateAttributes(ParsedAttributes &First, ParsedAttributes &Second, + ParsedAttributes &Result); + /// These constants match the enumerated choices of /// err_attribute_argument_n_type and err_attribute_argument_type. enum AttributeArgumentNType { diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4423,8 +4423,38 @@ // Helper for delayed processing of attributes. void ProcessDeclAttributeDelayed(Decl *D, const ParsedAttributesView &AttrList); - void ProcessDeclAttributeList(Scope *S, Decl *D, const ParsedAttributesView &AL, - bool IncludeCXX11Attributes = true); + + // Options for ProcessDeclAttributeList(). + struct ProcessDeclAttributeOptions { + ProcessDeclAttributeOptions() + : IncludeCXX11Attributes(true), IgnoreTypeAttributes(false) {} + + ProcessDeclAttributeOptions WithIncludeCXX11Attributes(bool Val) { + ProcessDeclAttributeOptions Result = *this; + Result.IncludeCXX11Attributes = Val; + return Result; + } + + ProcessDeclAttributeOptions WithIgnoreTypeAttributes(bool Val) { + ProcessDeclAttributeOptions Result = *this; + Result.IgnoreTypeAttributes = Val; + return Result; + } + + // Should C++11 attributes be processed? + bool IncludeCXX11Attributes; + + // Should any type attributes encountered be ignored? + // If this option is false, a diagnostic will be emitted for any type + // attributes of a kind that does not "slide" from the declaration to + // the decl-specifier-seq. + bool IgnoreTypeAttributes; + }; + + void ProcessDeclAttributeList(Scope *S, Decl *D, + const ParsedAttributesView &AttrList, + const ProcessDeclAttributeOptions &Options = + ProcessDeclAttributeOptions()); bool ProcessAccessDeclAttributeList(AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList); diff --git a/clang/lib/Basic/Attributes.cpp b/clang/lib/Basic/Attributes.cpp --- a/clang/lib/Basic/Attributes.cpp +++ b/clang/lib/Basic/Attributes.cpp @@ -85,6 +85,10 @@ return ScopeName && (ScopeName->isStr("gnu") || ScopeName->isStr("__gnu__")); } +bool AttributeCommonInfo::isClangScope() const { + return ScopeName && (ScopeName->isStr("clang") || ScopeName->isStr("_Clang")); +} + #include "clang/Sema/AttrParsedAttrKinds.inc" static SmallString<64> normalizeName(const IdentifierInfo *Name, diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1750,7 +1750,8 @@ /// Parser::DeclGroupPtrTy Parser::ParseDeclaration(DeclaratorContext Context, SourceLocation &DeclEnd, - ParsedAttributes &Attrs, + ParsedAttributes &DeclAttrs, + ParsedAttributes &DeclSpecAttrs, SourceLocation *DeclSpecStart) { ParenBraceBracketBalancer BalancerRAIIObj(*this); // Must temporarily exit the objective-c container scope for @@ -1761,32 +1762,40 @@ switch (Tok.getKind()) { case tok::kw_template: case tok::kw_export: - ProhibitAttributes(Attrs); - SingleDecl = ParseDeclarationStartingWithTemplate(Context, DeclEnd, Attrs); + ProhibitAttributes(DeclAttrs); + ProhibitAttributes(DeclSpecAttrs); + SingleDecl = + ParseDeclarationStartingWithTemplate(Context, DeclEnd, DeclAttrs); break; case tok::kw_inline: // Could be the start of an inline namespace. Allowed as an ext in C++03. if (getLangOpts().CPlusPlus && NextToken().is(tok::kw_namespace)) { - ProhibitAttributes(Attrs); + ProhibitAttributes(DeclAttrs); + ProhibitAttributes(DeclSpecAttrs); SourceLocation InlineLoc = ConsumeToken(); return ParseNamespace(Context, DeclEnd, InlineLoc); } - return ParseSimpleDeclaration(Context, DeclEnd, Attrs, true, nullptr, - DeclSpecStart); + return ParseSimpleDeclaration(Context, DeclEnd, DeclAttrs, DeclSpecAttrs, + true, nullptr, DeclSpecStart); case tok::kw_namespace: - ProhibitAttributes(Attrs); + ProhibitAttributes(DeclAttrs); + ProhibitAttributes(DeclSpecAttrs); return ParseNamespace(Context, DeclEnd); - case tok::kw_using: + case tok::kw_using: { + ParsedAttributes Attrs(AttrFactory); + ConcatenateAttributes(DeclAttrs, DeclSpecAttrs, Attrs); return ParseUsingDirectiveOrDeclaration(Context, ParsedTemplateInfo(), DeclEnd, Attrs); + } case tok::kw_static_assert: case tok::kw__Static_assert: - ProhibitAttributes(Attrs); + ProhibitAttributes(DeclAttrs); + ProhibitAttributes(DeclSpecAttrs); SingleDecl = ParseStaticAssertDeclaration(DeclEnd); break; default: - return ParseSimpleDeclaration(Context, DeclEnd, Attrs, true, nullptr, - DeclSpecStart); + return ParseSimpleDeclaration(Context, DeclEnd, DeclAttrs, DeclSpecAttrs, + true, nullptr, DeclSpecStart); } // This routine returns a DeclGroup, if the thing we parsed only contains a @@ -1816,7 +1825,8 @@ /// the Declaration. The SourceLocation for this Decl is set to /// DeclSpecStart if DeclSpecStart is non-null. Parser::DeclGroupPtrTy Parser::ParseSimpleDeclaration( - DeclaratorContext Context, SourceLocation &DeclEnd, ParsedAttributes &Attrs, + DeclaratorContext Context, SourceLocation &DeclEnd, + ParsedAttributes &DeclAttrs, ParsedAttributes &DeclSpecAttrs, bool RequireSemi, ForRangeInit *FRI, SourceLocation *DeclSpecStart) { // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this); @@ -1833,7 +1843,8 @@ // C99 6.7.2.3p6: Handle "struct-or-union identifier;", "enum { X };" // declaration-specifiers init-declarator-list[opt] ';' if (Tok.is(tok::semi)) { - ProhibitAttributes(Attrs); + ProhibitAttributes(DeclAttrs); + ProhibitAttributes(DeclSpecAttrs); DeclEnd = Tok.getLocation(); if (RequireSemi) ConsumeToken(); RecordDecl *AnonRecord = nullptr; @@ -1850,8 +1861,8 @@ if (DeclSpecStart) DS.SetRangeStart(*DeclSpecStart); - DS.takeAttributesFrom(Attrs); - return ParseDeclGroup(DS, Context, &DeclEnd, FRI); + DS.takeAttributesFrom(DeclSpecAttrs); + return ParseDeclGroup(DS, Context, DeclAttrs, &DeclEnd, FRI); } /// Returns true if this might be the start of a declarator, or a common typo @@ -2006,10 +2017,12 @@ /// result. Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context, + ParsedAttributes &Attrs, SourceLocation *DeclEnd, ForRangeInit *FRI) { // Parse the first declarator. ParsingDeclarator D(*this, DS, Context); + D.takeDeclarationAttributes(Attrs); ParseDeclarator(D); // Bail out if the first declarator didn't seem well-formed. @@ -2172,7 +2185,7 @@ } // Parse the next declarator. - D.clear(); + D.clearExceptDeclarationAttrs(); D.setCommaLoc(CommaLoc); // Accept attributes in an init-declarator. In the first declarator in a @@ -4300,7 +4313,6 @@ // Parse leading attributes. ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); - DS.takeAttributesFrom(Attrs); // Parse the common specifier-qualifiers-list piece. ParseSpecifierQualifierList(DS); @@ -4308,6 +4320,11 @@ // If there are no declarators, this is a free-standing declaration // specifier. Let the actions module cope with it. if (Tok.is(tok::semi)) { + // C2x draft 6.7.2.1/9 : "The optional attribute specifier sequence in a + // member declaration appertains to each of the members declared by the + // member declarator list; it shall not appear if the optional member + // declarator list is omitted." + ProhibitAttributes(Attrs); RecordDecl *AnonRecord = nullptr; Decl *TheDecl = Actions.ParsedFreeStandingDeclSpec(getCurScope(), AS_none, DS, AnonRecord); @@ -4321,6 +4338,7 @@ SourceLocation CommaLoc; while (true) { ParsingFieldDeclarator DeclaratorInfo(*this, DS); + DeclaratorInfo.D.takeDeclarationAttributes(Attrs); DeclaratorInfo.D.setCommaLoc(CommaLoc); // Attributes are only allowed here on successive declarators. @@ -4361,6 +4379,10 @@ return; FirstDeclarator = false; + + // Take the attributes back from the Declarator before we destroy it, so we + // can put them on the next field. + Attrs.takeAllFrom(DeclaratorInfo.D.getDeclarationAttributes()); } } @@ -6597,9 +6619,9 @@ /// declarator D up to a paren, which indicates that we are parsing function /// arguments. /// -/// If FirstArgAttrs is non-null, then the caller parsed those arguments -/// immediately after the open paren - they should be considered to be the -/// first argument of a parameter. +/// If FirstArgAttrs is non-null, then the caller parsed those attributes +/// immediately after the open paren - they will be applied to the DeclSpec +/// of the first parameter. /// /// If RequiresArg is true, then the first argument of the function is required /// to be present and required to not be an identifier list. @@ -6901,7 +6923,7 @@ /// /// DeclContext is the context of the declarator being parsed. If FirstArgAttrs /// is non-null, then the caller parsed those attributes immediately after the -/// open paren - they should be considered to be part of the first parameter. +/// open paren - they will be applied to the DeclSpec of the first parameter. /// /// After returning, ParamInfo will hold the parsed parameters. EllipsisLoc will /// be the location of the ellipsis, if any was parsed. @@ -6954,22 +6976,25 @@ DeclSpec DS(AttrFactory); // Parse any C++11 attributes. - MaybeParseCXX11Attributes(DS.getAttributes()); + ParsedAttributes ArgDeclAttrs(AttrFactory); + MaybeParseCXX11Attributes(ArgDeclAttrs); - // Skip any Microsoft attributes before a param. - MaybeParseMicrosoftAttributes(DS.getAttributes()); - - SourceLocation DSStart = Tok.getLocation(); + ParsedAttributes ArgDeclSpecAttrs(AttrFactory); // If the caller parsed attributes for the first argument, add them now. // Take them so that we only apply the attributes to the first parameter. // FIXME: If we can leave the attributes in the token stream somehow, we can // get rid of a parameter (FirstArgAttrs) and this statement. It might be // too much hassle. - DS.takeAttributesFrom(FirstArgAttrs); + ArgDeclSpecAttrs.takeAllFrom(FirstArgAttrs); - ParseDeclarationSpecifiers(DS); + // Skip any Microsoft attributes before a param. + MaybeParseMicrosoftAttributes(ArgDeclSpecAttrs); + + SourceLocation DSStart = Tok.getLocation(); + ParseDeclarationSpecifiers(DS); + DS.takeAttributesFrom(ArgDeclSpecAttrs); // Parse the declarator. This is "PrototypeContext" or // "LambdaExprParameterContext", because we must accept either @@ -6980,6 +7005,7 @@ : DeclaratorCtx == DeclaratorContext::LambdaExpr ? DeclaratorContext::LambdaExprParameter : DeclaratorContext::Prototype); + ParmDeclarator.takeDeclarationAttributes(ArgDeclAttrs); ParseDeclarator(ParmDeclarator); // Parse GNU attributes, if present. diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -342,7 +342,8 @@ /// 'extern' string-literal '{' declaration-seq[opt] '}' /// 'extern' string-literal declaration /// -Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context) { +Decl *Parser::ParseLinkage(ParsingDeclSpec &DS, DeclaratorContext Context, + ParsedAttributes &DeclAttrs) { assert(isTokenStringLiteral() && "Not a string literal!"); ExprResult Lang = ParseStringLiteralExpression(false); @@ -354,8 +355,7 @@ getCurScope(), DS.getSourceRange().getBegin(), Lang.get(), Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation()); - ParsedAttributes attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(DeclAttrs); if (Tok.isNot(tok::l_brace)) { // Reset the source range in DS, as the leading "extern" @@ -364,7 +364,7 @@ DS.SetRangeEnd(SourceLocation()); // ... but anyway remember that such an "extern" was seen. DS.setExternInLinkageSpec(true); - ParseExternalDeclaration(attrs, &DS); + ParseExternalDeclaration(DeclAttrs, &DS); return LinkageSpec ? Actions.ActOnFinishLinkageSpecification( getCurScope(), LinkageSpec, SourceLocation()) : nullptr; @@ -372,7 +372,7 @@ DS.abort(); - ProhibitAttributes(attrs); + ProhibitAttributes(DeclAttrs); BalancedDelimiterTracker T(*this, tok::l_brace); T.consumeOpen(); @@ -2676,23 +2676,24 @@ TemplateInfo, TemplateDiags); } - ParsedAttributes attrs(AttrFactory); - ParsedAttributesView FnAttrs; + ParsedAttributes DeclAttrs(AttrFactory); // Optional C++11 attribute-specifier - MaybeParseCXX11Attributes(attrs); + MaybeParseCXX11Attributes(DeclAttrs); // The next token may be an OpenMP pragma annotation token. That would // normally be handled from ParseCXXClassMemberDeclarationWithPragmas, but in // this case, it came from an *attribute* rather than a pragma. Handle it now. if (Tok.is(tok::annot_attr_openmp)) - return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, attrs); + return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, DeclAttrs); - // We need to keep these attributes for future diagnostic - // before they are taken over by declaration specifier. - FnAttrs.addAll(attrs.begin(), attrs.end()); - FnAttrs.Range = attrs.Range; + // We need to keep these attributes for future diagnostics + // before they are taken over by the declaration. + ParsedAttributesView FnAttrs; + FnAttrs.addAll(DeclAttrs.begin(), DeclAttrs.end()); + FnAttrs.Range = DeclAttrs.Range; - MaybeParseMicrosoftAttributes(attrs); + ParsedAttributes DeclSpecAttrs(AttrFactory); + MaybeParseMicrosoftAttributes(DeclSpecAttrs); if (Tok.is(tok::kw_using)) { // Eat 'using'. @@ -2713,7 +2714,7 @@ SourceLocation DeclEnd; // Otherwise, it must be a using-declaration or an alias-declaration. return ParseUsingDeclaration(DeclaratorContext::Member, TemplateInfo, - UsingLoc, DeclEnd, attrs, AS); + UsingLoc, DeclEnd, DeclAttrs, AS); } // Hold late-parsed attributes so we can attach a Decl to them later. @@ -2722,7 +2723,8 @@ // decl-specifier-seq: // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this, TemplateDiags); - DS.takeAttributesFrom(attrs); + DS.takeAttributesFrom(DeclSpecAttrs); + if (MalformedTypeSpec) DS.SetTypeSpecError(); @@ -2774,6 +2776,7 @@ } ParsingDeclarator DeclaratorInfo(*this, DS, DeclaratorContext::Member); + DeclaratorInfo.takeDeclarationAttributes(DeclAttrs); if (TemplateInfo.TemplateParams) DeclaratorInfo.setTemplateParameterLists(TemplateParams); VirtSpecifiers VS; @@ -3072,7 +3075,7 @@ } // Parse the next declarator. - DeclaratorInfo.clear(); + DeclaratorInfo.clearExceptDeclarationAttrs(); VS.clear(); BitfieldSize = ExprResult(/*Invalid=*/false); EqualLoc = PureSpecLoc = SourceLocation(); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -2048,9 +2048,11 @@ if (Tok.is(tok::kw_using)) DG = ParseAliasDeclarationInInitStatement( DeclaratorContext::SelectionInit, attrs); - else + else { + ParsedAttributes DeclSpecAttrs(AttrFactory); DG = ParseSimpleDeclaration(DeclaratorContext::SelectionInit, DeclEnd, - attrs, /*RequireSemi=*/true); + attrs, DeclSpecAttrs, /*RequireSemi=*/true); + } *InitStmt = Actions.ActOnDeclStmt(DG, DeclStart, DeclEnd); return ParseCXXCondition(nullptr, Loc, CK, MissingOK); } @@ -2061,8 +2063,9 @@ // permitted here. assert(FRI && "should not parse a for range declaration here"); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy DG = ParseSimpleDeclaration(DeclaratorContext::ForInit, - DeclEnd, attrs, false, FRI); + ParsedAttributes DeclSpecAttrs(AttrFactory); + DeclGroupPtrTy DG = ParseSimpleDeclaration( + DeclaratorContext::ForInit, DeclEnd, attrs, DeclSpecAttrs, false, FRI); FRI->LoopVar = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); assert((FRI->ColonLoc.isValid() || !DG) && "cannot find for range declaration"); @@ -2079,11 +2082,11 @@ // type-specifier-seq DeclSpec DS(AttrFactory); - DS.takeAttributesFrom(attrs); ParseSpecifierQualifierList(DS, AS_none, DeclSpecContext::DSC_condition); // declarator Declarator DeclaratorInfo(DS, DeclaratorContext::Condition); + DeclaratorInfo.takeDeclarationAttributes(attrs); ParseDeclarator(DeclaratorInfo); // simple-asm-expr[opt] diff --git a/clang/lib/Parse/ParseObjc.cpp b/clang/lib/Parse/ParseObjc.cpp --- a/clang/lib/Parse/ParseObjc.cpp +++ b/clang/lib/Parse/ParseObjc.cpp @@ -658,7 +658,7 @@ if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) { SourceLocation DeclEnd; allTUVariables.push_back( - ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs)); + ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs, attrs)); continue; } @@ -1231,6 +1231,7 @@ // Now actually move the attributes over. takeDeclAttributes(attrs, D.getMutableDeclSpec().getAttributes()); + takeDeclAttributes(attrs, D.getDeclarationAttributes()); takeDeclAttributes(attrs, D.getAttributes()); for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) takeDeclAttributes(attrs, D.getTypeObject(i).getAttrs()); diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -105,15 +105,21 @@ // statement are different from [[]] attributes that follow an __attribute__ // at the start of the statement. Thus, we're not using MaybeParseAttributes // here because we don't want to allow arbitrary orderings. - ParsedAttributes Attrs(AttrFactory); - MaybeParseCXX11Attributes(Attrs, /*MightBeObjCMessageSend*/ true); + ParsedAttributes CXX11Attrs(AttrFactory); + MaybeParseCXX11Attributes(CXX11Attrs, /*MightBeObjCMessageSend*/ true); + ParsedAttributes GNUAttrs(AttrFactory); if (getLangOpts().OpenCL) - MaybeParseGNUAttributes(Attrs); + MaybeParseGNUAttributes(GNUAttrs); StmtResult Res = ParseStatementOrDeclarationAfterAttributes( - Stmts, StmtCtx, TrailingElseLoc, Attrs); + Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs, GNUAttrs); MaybeDestroyTemplateIds(); + // Attributes that are left should all go on the statement, so concatenate the + // two lists. + ParsedAttributes Attrs(AttrFactory); + ConcatenateAttributes(CXX11Attrs, GNUAttrs, Attrs); + assert((Attrs.empty() || Res.isInvalid() || Res.isUsable()) && "attributes on empty statement"); @@ -158,7 +164,8 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( StmtVector &Stmts, ParsedStmtContext StmtCtx, - SourceLocation *TrailingElseLoc, ParsedAttributes &Attrs) { + SourceLocation *TrailingElseLoc, ParsedAttributes &CXX11Attrs, + ParsedAttributes &GNUAttrs) { const char *SemiError = nullptr; StmtResult Res; SourceLocation GNUAttributeLoc; @@ -184,6 +191,12 @@ case tok::identifier: { Token Next = NextToken(); if (Next.is(tok::colon)) { // C99 6.8.1: labeled-statement + // Both C++11 and GNU attributes preceding the label appertain to the + // label, so put them in a single list to pass on to + // ParseLabeledStatement(). + ParsedAttributes Attrs(AttrFactory); + ConcatenateAttributes(CXX11Attrs, GNUAttrs, Attrs); + // identifier ':' statement return ParseLabeledStatement(Attrs, StmtCtx); } @@ -213,25 +226,29 @@ } default: { + auto isStmtAttr = [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }; if ((getLangOpts().CPlusPlus || getLangOpts().MicrosoftExt || (StmtCtx & ParsedStmtContext::AllowDeclarationsInC) != ParsedStmtContext()) && ((GNUAttributeLoc.isValid() && - !(!Attrs.empty() && - llvm::all_of( - Attrs, [](ParsedAttr &Attr) { return Attr.isStmtAttr(); }))) || + !(!(CXX11Attrs.empty() && GNUAttrs.empty()) && + llvm::all_of(CXX11Attrs, isStmtAttr) && + llvm::all_of(GNUAttrs, isStmtAttr))) || isDeclarationStatement())) { SourceLocation DeclStart = Tok.getLocation(), DeclEnd; DeclGroupPtrTy Decl; if (GNUAttributeLoc.isValid()) { DeclStart = GNUAttributeLoc; - Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, Attrs, - &GNUAttributeLoc); + Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, CXX11Attrs, + GNUAttrs, &GNUAttributeLoc); } else { - Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, Attrs); + Decl = ParseDeclaration(DeclaratorContext::Block, DeclEnd, CXX11Attrs, + GNUAttrs); } - if (Attrs.Range.getBegin().isValid()) - DeclStart = Attrs.Range.getBegin(); + if (CXX11Attrs.Range.getBegin().isValid()) + DeclStart = CXX11Attrs.Range.getBegin(); + else if (GNUAttrs.Range.getBegin().isValid()) + DeclStart = GNUAttrs.Range.getBegin(); return Actions.ActOnDeclStmt(Decl, DeclStart, DeclEnd); } @@ -245,7 +262,7 @@ case tok::kw___attribute: { GNUAttributeLoc = Tok.getLocation(); - ParseGNUAttributes(Attrs); + ParseGNUAttributes(GNUAttrs); goto Retry; } @@ -297,7 +314,8 @@ break; case tok::kw_asm: { - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); bool msAsm = false; Res = ParseAsmStatement(msAsm); Res = Actions.ActOnFinishFullStmt(Res.get()); @@ -308,7 +326,8 @@ case tok::kw___if_exists: case tok::kw___if_not_exists: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); ParseMicrosoftIfExistsStatement(Stmts); // An __if_exists block is like a compound statement, but it doesn't create // a new scope. @@ -318,7 +337,8 @@ return ParseCXXTryBlock(); case tok::kw___try: - ProhibitAttributes(Attrs); // TODO: is it correct? + ProhibitAttributes(CXX11Attrs); // TODO: is it correct? + ProhibitAttributes(GNUAttrs); return ParseSEHTryBlock(); case tok::kw___leave: @@ -327,55 +347,65 @@ break; case tok::annot_pragma_vis: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaVisibility(); return StmtEmpty(); case tok::annot_pragma_pack: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaPack(); return StmtEmpty(); case tok::annot_pragma_msstruct: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaMSStruct(); return StmtEmpty(); case tok::annot_pragma_align: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaAlign(); return StmtEmpty(); case tok::annot_pragma_weak: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaWeak(); return StmtEmpty(); case tok::annot_pragma_weakalias: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaWeakAlias(); return StmtEmpty(); case tok::annot_pragma_redefine_extname: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaRedefineExtname(); return StmtEmpty(); case tok::annot_pragma_fp_contract: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "fp_contract"; ConsumeAnnotationToken(); return StmtError(); case tok::annot_pragma_fp: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "clang fp"; ConsumeAnnotationToken(); return StmtError(); case tok::annot_pragma_fenv_access: case tok::annot_pragma_fenv_access_ms: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << (Kind == tok::annot_pragma_fenv_access ? "STDC FENV_ACCESS" : "fenv_access"); @@ -383,53 +413,62 @@ return StmtEmpty(); case tok::annot_pragma_fenv_round: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "STDC FENV_ROUND"; ConsumeAnnotationToken(); return StmtError(); case tok::annot_pragma_float_control: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); Diag(Tok, diag::err_pragma_file_or_compound_scope) << "float_control"; ConsumeAnnotationToken(); return StmtError(); case tok::annot_pragma_opencl_extension: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaOpenCLExtension(); return StmtEmpty(); case tok::annot_pragma_captured: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); return HandlePragmaCaptured(); case tok::annot_pragma_openmp: // Prohibit attributes that are not OpenMP attributes, but only before // processing a #pragma omp clause. - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); LLVM_FALLTHROUGH; case tok::annot_attr_openmp: // Do not prohibit attributes if they were OpenMP attributes. return ParseOpenMPDeclarativeOrExecutableDirective(StmtCtx); case tok::annot_pragma_ms_pointers_to_members: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaMSPointersToMembers(); return StmtEmpty(); case tok::annot_pragma_ms_pragma: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaMSPragma(); return StmtEmpty(); case tok::annot_pragma_ms_vtordisp: - ProhibitAttributes(Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); HandlePragmaMSVtorDisp(); return StmtEmpty(); case tok::annot_pragma_loop_hint: - ProhibitAttributes(Attrs); - return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, Attrs); + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); + return ParsePragmaLoopHint(Stmts, StmtCtx, TrailingElseLoc, CXX11Attrs); case tok::annot_pragma_dump: HandlePragmaDump(); @@ -658,8 +697,9 @@ Attrs.takeAllFrom(TempAttrs); else { StmtVector Stmts; - SubStmt = ParseStatementOrDeclarationAfterAttributes(Stmts, StmtCtx, - nullptr, TempAttrs); + ParsedAttributes EmptyCXX11Attrs(AttrFactory); + SubStmt = ParseStatementOrDeclarationAfterAttributes( + Stmts, StmtCtx, nullptr, EmptyCXX11Attrs, TempAttrs); if (!TempAttrs.empty() && !SubStmt.isInvalid()) SubStmt = Actions.ActOnAttributedStmt(TempAttrs, SubStmt.get()); } @@ -1128,8 +1168,9 @@ ExtensionRAIIObject O(Diags); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; - DeclGroupPtrTy Res = - ParseDeclaration(DeclaratorContext::Block, DeclEnd, attrs); + ParsedAttributes DeclSpecAttrs(AttrFactory); + DeclGroupPtrTy Res = ParseDeclaration(DeclaratorContext::Block, DeclEnd, + attrs, DeclSpecAttrs); R = Actions.ActOnDeclStmt(Res, DeclStart, DeclEnd); } else { // Otherwise this was a unary __extension__ marker. @@ -1975,8 +2016,9 @@ ColonProtectionRAIIObject ColonProtection(*this, MightBeForRangeStmt); SourceLocation DeclStart = Tok.getLocation(), DeclEnd; + ParsedAttributes DeclSpecAttrs(AttrFactory); DG = ParseSimpleDeclaration( - DeclaratorContext::ForInit, DeclEnd, attrs, false, + DeclaratorContext::ForInit, DeclEnd, attrs, DeclSpecAttrs, false, MightBeForRangeStmt ? &ForRangeInfo : nullptr); FirstPart = Actions.ActOnDeclStmt(DG, DeclStart, Tok.getLocation()); if (ForRangeInfo.ParsedForRangeDecl()) { @@ -2347,8 +2389,9 @@ // Get the next statement. MaybeParseCXX11Attributes(Attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); StmtResult S = ParseStatementOrDeclarationAfterAttributes( - Stmts, StmtCtx, TrailingElseLoc, Attrs); + Stmts, StmtCtx, TrailingElseLoc, Attrs, EmptyDeclSpecAttrs); Attrs.takeAllFrom(TempAttrs); @@ -2584,12 +2627,12 @@ MaybeParseCXX11Attributes(Attributes); DeclSpec DS(AttrFactory); - DS.takeAttributesFrom(Attributes); if (ParseCXXTypeSpecifierSeq(DS)) return StmtError(); Declarator ExDecl(DS, DeclaratorContext::CXXCatch); + ExDecl.takeDeclarationAttributes(Attributes); ParseDeclarator(ExDecl); ExceptionDecl = Actions.ActOnExceptionDeclarator(getCurScope(), ExDecl); } else diff --git a/clang/lib/Parse/ParseTemplate.cpp b/clang/lib/Parse/ParseTemplate.cpp --- a/clang/lib/Parse/ParseTemplate.cpp +++ b/clang/lib/Parse/ParseTemplate.cpp @@ -242,11 +242,10 @@ // Move the attributes from the prefix into the DS. if (TemplateInfo.Kind == ParsedTemplateInfo::ExplicitInstantiation) ProhibitAttributes(prefixAttrs); - else - DS.takeAttributesFrom(prefixAttrs); // Parse the declarator. ParsingDeclarator DeclaratorInfo(*this, DS, (DeclaratorContext)Context); + DeclaratorInfo.takeDeclarationAttributes(prefixAttrs); if (TemplateInfo.TemplateParams) DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams); diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -740,6 +740,9 @@ /// ParseExternalDeclaration: /// +/// The `Attrs that are passed in are C++11 attributes and appertain to the +/// declaration. +/// /// external-declaration: [C99 6.9], declaration: [C++ dcl.dcl] /// function-definition /// declaration @@ -929,7 +932,9 @@ // A function definition cannot start with any of these keywords. { SourceLocation DeclEnd; - return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs); + ParsedAttributes DeclSpecAttrs(AttrFactory); + return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, + DeclSpecAttrs); } case tok::kw_static: @@ -939,7 +944,9 @@ Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) << 0; SourceLocation DeclEnd; - return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, + EmptyDeclSpecAttrs); } goto dont_know; @@ -950,7 +957,9 @@ // Inline namespaces. Allowed as an extension even in C++03. if (NextKind == tok::kw_namespace) { SourceLocation DeclEnd; - return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, + EmptyDeclSpecAttrs); } // Parse (then ignore) 'inline' prior to a template instantiation. This is @@ -959,7 +968,9 @@ Diag(ConsumeToken(), diag::warn_static_inline_explicit_inst_ignored) << 1; SourceLocation DeclEnd; - return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, + EmptyDeclSpecAttrs); } } goto dont_know; @@ -1112,8 +1123,6 @@ return Actions.ConvertDeclToDeclGroup(TheDecl); } - DS.takeAttributesFrom(Attrs); - // ObjC2 allows prefix attributes on class interfaces and protocols. // FIXME: This still needs better diagnostics. We should only accept // attributes here, no types, etc. @@ -1128,6 +1137,7 @@ } DS.abort(); + DS.takeAttributesFrom(Attrs); const char *PrevSpec = nullptr; unsigned DiagID; @@ -1151,11 +1161,11 @@ if (getLangOpts().CPlusPlus && isTokenStringLiteral() && DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { - Decl *TheDecl = ParseLinkage(DS, DeclaratorContext::File); + Decl *TheDecl = ParseLinkage(DS, DeclaratorContext::File, Attrs); return Actions.ConvertDeclToDeclGroup(TheDecl); } - return ParseDeclGroup(DS, DeclaratorContext::File); + return ParseDeclGroup(DS, DeclaratorContext::File, Attrs); } Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition( diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -212,6 +212,40 @@ return getInfo().IsSupportedByPragmaAttribute; } +bool ParsedAttr::slidesFromDeclToDeclSpec() const { + if (!isTypeAttr()) + return false; + if (!isStandardAttributeSyntax()) + return true; + + // We have historically allowed some attributes with standard attribute syntax + // to slide to the decl-specifier-seq, so we have to keep supporting it. This + // property is consciously not defined as a flag in Attr.td because we don't + // want new attributes to specify it. + switch (getParsedKind()) { + case AT_AddressSpace: + case AT_OpenCLPrivateAddressSpace: + case AT_OpenCLGlobalAddressSpace: + case AT_OpenCLGlobalDeviceAddressSpace: + case AT_OpenCLGlobalHostAddressSpace: + case AT_OpenCLLocalAddressSpace: + case AT_OpenCLConstantAddressSpace: + case AT_OpenCLGenericAddressSpace: + case AT_NeonPolyVectorType: + case AT_NeonVectorType: + case AT_ArmMveStrictPolymorphism: + case AT_BTFTypeTag: + case AT_Regparm: + case AT_NoDeref: + case AT_ObjCGC: + case AT_VectorSize: + case AT_MatrixType: + return true; + default: + return false; + } +} + bool ParsedAttr::acceptsExprPack() const { return getInfo().AcceptsExprPack; } unsigned ParsedAttr::getSemanticSpelling() const { @@ -265,3 +299,20 @@ diag::err_attribute_too_many_arguments, std::greater()); } + +void clang::ConcatenateAttributes(ParsedAttributes &First, + ParsedAttributes &Second, + ParsedAttributes &Result) { + // Note that takeAllFrom() puts the attributes at the beginning of the list, + // so to obtain the correct ordering, we add `Second`, then `First`. + Result.takeAllFrom(Second); + Result.takeAllFrom(First); + if (First.Range.getBegin().isValid()) + Result.Range.setBegin(First.Range.getBegin()); + else + Result.Range.setBegin(Second.Range.getBegin()); + if (Second.Range.getEnd().isValid()) + Result.Range.setEnd(Second.Range.getEnd()); + else + Result.Range.setEnd(First.Range.getEnd()); +} diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -7027,7 +7027,8 @@ } // Finally, check attributes on the decl itself. - return PD.getAttributes().hasAttribute(Kind); + return PD.getAttributes().hasAttribute(Kind) || + PD.getDeclarationAttributes().hasAttribute(Kind); } /// Adjust the \c DeclContext for a function or variable that might be a diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -8312,15 +8312,15 @@ /// 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. -static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, - const ParsedAttr &AL, - bool IncludeCXX11Attributes) { +static void +ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, + const Sema::ProcessDeclAttributeOptions &Options) { if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute) return; // Ignore C++11 attributes on declarator chunks: they appertain to the type // instead. - if (AL.isCXX11Attribute() && !IncludeCXX11Attributes) + if (AL.isCXX11Attribute() && !Options.IncludeCXX11Attributes) return; // Unknown attributes are automatically warned on. Target-specific attributes @@ -8353,14 +8353,29 @@ if (AL.getInfo().handleDeclAttribute(S, D, AL) != ParsedAttrInfo::NotHandled) break; if (!AL.isStmtAttr()) { - // Type attributes are handled elsewhere; silently move on. assert(AL.isTypeAttr() && "Non-type attribute not handled"); - break; + } + if (AL.isTypeAttr()) { + if (Options.IgnoreTypeAttributes) + break; + if (AL.slidesFromDeclToDeclSpec()) { + if (AL.isStandardAttributeSyntax() && AL.isClangScope()) { + // For standard syntax attributes, which would normally appertain to + // the declaration here, suggest moving them to the type instead. But + // only do this for our own vendor attributes; moving other vendors' + // attributes might hurt portability. + S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl) + << AL << D->getLocation(); + } + // GNU type attributes are handled elsewhere; silently move on. + break; + } } // N.B., ClangAttrEmitter.cpp emits a diagnostic helper that ensures a // statement attribute is not written on a declaration, but this code is - // needed for attributes in Attr.td that do not list any subjects. - S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl) + // needed for type attributes as well as statement attributes in Attr.td + // that do not list any subjects. + S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl) << AL << D->getLocation(); break; case ParsedAttr::AT_Interrupt: @@ -9004,14 +9019,14 @@ /// ProcessDeclAttributeList - Apply all the decl attributes in the specified /// attribute list to the specified decl, ignoring any type attributes. -void Sema::ProcessDeclAttributeList(Scope *S, Decl *D, - const ParsedAttributesView &AttrList, - bool IncludeCXX11Attributes) { +void Sema::ProcessDeclAttributeList( + Scope *S, Decl *D, const ParsedAttributesView &AttrList, + const ProcessDeclAttributeOptions &Options) { if (AttrList.empty()) return; for (const ParsedAttr &AL : AttrList) - ProcessDeclAttribute(*this, S, D, AL, IncludeCXX11Attributes); + ProcessDeclAttribute(*this, S, D, AL, Options); // FIXME: We should be able to handle these cases in TableGen. // GCC accepts @@ -9099,7 +9114,9 @@ AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) { for (const ParsedAttr &AL : AttrList) { if (AL.getKind() == ParsedAttr::AT_Annotate) { - ProcessDeclAttribute(*this, nullptr, ASDecl, AL, AL.isCXX11Attribute()); + ProcessDeclAttributeOptions Options; + Options.IncludeCXX11Attributes = AL.isCXX11Attribute(); + ProcessDeclAttribute(*this, nullptr, ASDecl, AL, Options); } else { Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec); return true; @@ -9133,6 +9150,7 @@ /// which might be lying around on it. void Sema::checkUnusedDeclAttributes(Declarator &D) { ::checkUnusedDeclAttributes(*this, D.getDeclSpec().getAttributes()); + ::checkUnusedDeclAttributes(*this, D.getDeclarationAttributes()); ::checkUnusedDeclAttributes(*this, D.getAttributes()); for (unsigned i = 0, e = D.getNumTypeObjects(); i != e; ++i) ::checkUnusedDeclAttributes(*this, D.getTypeObject(i).getAttrs()); @@ -9241,18 +9259,34 @@ /// specified in many different places, and we need to find and apply them all. void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { // Apply decl attributes from the DeclSpec if present. - if (!PD.getDeclSpec().getAttributes().empty()) - ProcessDeclAttributeList(S, D, PD.getDeclSpec().getAttributes()); + if (!PD.getDeclSpec().getAttributes().empty()) { + ProcessDeclAttributeList( + S, D, PD.getDeclSpec().getAttributes(), + ProcessDeclAttributeOptions().WithIgnoreTypeAttributes(true)); + } // Walk the declarator structure, applying decl attributes that were in a type // position to the decl itself. This handles cases like: // int *__attr__(x)** D; // when X is a decl attribute. - for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) + for (unsigned i = 0, e = PD.getNumTypeObjects(); i != e; ++i) { ProcessDeclAttributeList(S, D, PD.getTypeObject(i).getAttrs(), - /*IncludeCXX11Attributes=*/false); + ProcessDeclAttributeOptions() + .WithIncludeCXX11Attributes(false) + .WithIgnoreTypeAttributes(true)); + } // Finally, apply any attributes on the decl itself. + // Ordering of attributes can be important, so we first process the attributes + // from the declaration, and then those from the DeclSpec, as this corresponds + // to the order in which they appeared in the source code. + ParsedAttributesView NonSlidingAttrs; + for (ParsedAttr &AL : PD.getDeclarationAttributes()) { + if (!AL.slidesFromDeclToDeclSpec()) { + NonSlidingAttrs.addAtEnd(&AL); + } + } + ProcessDeclAttributeList(S, D, NonSlidingAttrs); ProcessDeclAttributeList(S, D, PD.getAttributes()); // Apply additional attributes specified by '#pragma clang attribute'. diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -197,6 +197,10 @@ /// validating that noderef was used on a pointer or array. bool parsedNoDeref; + // Set to indicate that, if we're currently processing the DeclSpec, the + // attributes we're seeing were actually written ahead of the declaration. + bool isProcessingDeclarationAttrs = false; + public: TypeProcessingState(Sema &sema, Declarator &declarator) : sema(sema), declarator(declarator), @@ -224,7 +228,14 @@ chunkIndex = idx; } + void setIsProcessingDeclarationAttrs(bool val) { + assert(isProcessingDeclSpec()); + isProcessingDeclarationAttrs = val; + } + ParsedAttributesView &getCurrentAttributes() const { + if (isProcessingDeclarationAttrs) + return declarator.getDeclarationAttributes(); if (isProcessingDeclSpec()) return getMutableDeclSpec().getAttributes(); return declarator.getTypeObject(chunkIndex).getAttrs(); @@ -525,7 +536,8 @@ /// Distribute an objc_gc type attribute that was written on the /// declarator. static void distributeObjCPointerTypeAttrFromDeclarator( - TypeProcessingState &state, ParsedAttr &attr, QualType &declSpecType) { + TypeProcessingState &state, ParsedAttributes &Attrs, ParsedAttr &attr, + QualType &declSpecType) { Declarator &declarator = state.getDeclarator(); // objc_gc goes on the innermost pointer to something that's not a @@ -562,8 +574,7 @@ // attribute from being applied multiple times and gives // the source-location-filler something to work with. state.saveDeclSpecAttrs(); - declarator.getMutableDeclSpec().getAttributes().takeOneFrom( - declarator.getAttributes(), &attr); + declarator.getMutableDeclSpec().getAttributes().takeOneFrom(Attrs, &attr); return; } } @@ -571,15 +582,15 @@ // Otherwise, if we found an appropriate chunk, splice the attribute // into it. if (innermost != -1U) { - moveAttrFromListToList(attr, declarator.getAttributes(), + moveAttrFromListToList(attr, Attrs, declarator.getTypeObject(innermost).getAttrs()); return; } // Otherwise, diagnose when we're done building the type. - declarator.getAttributes().remove(&attr); + Attrs.remove(&attr); state.addIgnoredTypeAttr(attr); -} + } /// A function type attribute was written somewhere in a declaration /// *other* than on the declarator itself or in the decl spec. Given @@ -640,15 +651,6 @@ QualType &declSpecType) { state.saveDeclSpecAttrs(); - // C++11 attributes before the decl specifiers actually appertain to - // the declarators. Move them straight there. We don't support the - // 'put them wherever you like' semantics we allow for GNU attributes. - if (attr.isStandardAttributeSyntax()) { - moveAttrFromListToList(attr, state.getCurrentAttributes(), - state.getDeclarator().getAttributes()); - return; - } - // Try to distribute to the innermost. if (distributeFunctionTypeAttrToInnermost( state, attr, state.getCurrentAttributes(), declSpecType)) @@ -659,25 +661,25 @@ state.addIgnoredTypeAttr(attr); } -/// A function type attribute was written on the declarator. Try to -/// apply it somewhere. +/// A function type attribute was written on the declarator or declaration. +/// Try to apply it somewhere. +/// `Attrs` is the attribute list containing the declaration (either of the +/// declarator or the declaration). static void distributeFunctionTypeAttrFromDeclarator(TypeProcessingState &state, + ParsedAttributes &Attrs, ParsedAttr &attr, QualType &declSpecType) { - Declarator &declarator = state.getDeclarator(); - // Try to distribute to the innermost. - if (distributeFunctionTypeAttrToInnermost( - state, attr, declarator.getAttributes(), declSpecType)) + if (distributeFunctionTypeAttrToInnermost(state, attr, Attrs, declSpecType)) return; // If that failed, diagnose the bad attribute when the declarator is // fully built. - declarator.getAttributes().remove(&attr); + Attrs.remove(&attr); state.addIgnoredTypeAttr(attr); } -/// Given that there are attributes written on the declarator +/// Given that there are attributes written on the declarator or declaration /// itself, try to distribute any type attributes to the appropriate /// declarator chunk. /// @@ -686,15 +688,16 @@ /// int (f ATTR)(); /// but not necessarily this: /// int f() ATTR; +/// +/// `Attrs` is the attribute list containing the declaration (either of the +/// declarator or the declaration). static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, + ParsedAttributes &Attrs, QualType &declSpecType) { - // Collect all the type attributes from the declarator itself. - assert(!state.getDeclarator().getAttributes().empty() && - "declarator has no attrs!"); // The called functions in this loop actually remove things from the current // list, so iterating over the existing list isn't possible. Instead, make a // non-owning copy and iterate over that. - ParsedAttributesView AttrsCopy{state.getDeclarator().getAttributes()}; + ParsedAttributesView AttrsCopy{Attrs}; for (ParsedAttr &attr : AttrsCopy) { // Do not distribute [[]] attributes. They have strict rules for what // they appertain to. @@ -703,11 +706,13 @@ switch (attr.getKind()) { OBJC_POINTER_TYPE_ATTRS_CASELIST: - distributeObjCPointerTypeAttrFromDeclarator(state, attr, declSpecType); + distributeObjCPointerTypeAttrFromDeclarator(state, Attrs, attr, + declSpecType); break; FUNCTION_TYPE_ATTRS_CASELIST: - distributeFunctionTypeAttrFromDeclarator(state, attr, declSpecType); + distributeFunctionTypeAttrFromDeclarator(state, Attrs, attr, + declSpecType); break; MS_TYPE_ATTRS_CASELIST: @@ -1804,8 +1809,31 @@ // list of type attributes to be temporarily saved while the type // attributes are pushed around. // pipe attributes will be handled later ( at GetFullTypeForDeclarator ) - if (!DS.isTypeSpecPipe()) + if (!DS.isTypeSpecPipe()) { + // We also apply declaration attributes that "slide" to the decl spec. + // Ordering can be important for attributes. The decalaration attributes + // come syntactically before the decl spec attributes, so we process them + // in that order. + ParsedAttributesView SlidingAttrs; + for (ParsedAttr &AL : declarator.getDeclarationAttributes()) { + if (AL.slidesFromDeclToDeclSpec()) { + SlidingAttrs.addAtEnd(&AL); + + // For standard syntax attributes, which would normally appertain to the + // declaration here, suggest moving them to the type instead. But only + // do this for our own vendor attributes; moving other vendors' + // attributes might hurt portability. + if (AL.isStandardAttributeSyntax() && AL.isClangScope()) { + S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl) + << AL; + } + } + } + state.setIsProcessingDeclarationAttrs(true); + processTypeAttrs(state, Result, TAL_DeclSpec, SlidingAttrs); + state.setIsProcessingDeclarationAttrs(false); processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes()); + } // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -3412,8 +3440,8 @@ break; } - if (!D.getAttributes().empty()) - distributeTypeAttrsFromDeclarator(state, T); + distributeTypeAttrsFromDeclarator(state, D.getDeclarationAttributes(), T); + distributeTypeAttrsFromDeclarator(state, D.getAttributes(), T); // Find the deduced type in this type. Look in the trailing return type if we // have one, otherwise in the DeclSpec type. @@ -4712,7 +4740,8 @@ AttrList.hasAttribute(ParsedAttr::AT_CFReturnsNotRetained); }; if (const auto *InnermostChunk = D.getInnermostNonParenChunk()) { - if (hasCFReturnsAttr(D.getAttributes()) || + if (hasCFReturnsAttr(D.getDeclarationAttributes()) || + hasCFReturnsAttr(D.getAttributes()) || hasCFReturnsAttr(InnermostChunk->getAttrs()) || hasCFReturnsAttr(D.getDeclSpec().getAttributes())) { inferNullability = NullabilityKind::Nullable; @@ -5282,7 +5311,9 @@ // function is marked with the "overloadable" attribute. Scan // for this attribute now. if (!FTI.NumParams && FTI.isVariadic && !LangOpts.CPlusPlus) - if (!D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable) && + if (!D.getDeclarationAttributes().hasAttribute( + ParsedAttr::AT_Overloadable) && + !D.getAttributes().hasAttribute(ParsedAttr::AT_Overloadable) && !D.getDeclSpec().getAttributes().hasAttribute( ParsedAttr::AT_Overloadable)) S.Diag(FTI.getEllipsisLoc(), diag::err_ellipsis_first_param); @@ -5696,7 +5727,14 @@ } } - // Apply any undistributed attributes from the declarator. + // Apply any undistributed attributes from the declaration or declarator. + ParsedAttributesView NonSlidingAttrs; + for (ParsedAttr &AL : D.getDeclarationAttributes()) { + if (!AL.slidesFromDeclToDeclSpec()) { + NonSlidingAttrs.addAtEnd(&AL); + } + } + processTypeAttrs(state, T, TAL_DeclName, NonSlidingAttrs); processTypeAttrs(state, T, TAL_DeclName, D.getAttributes()); // Diagnose any ignored type attributes. diff --git a/clang/test/Sema/annotate-type.c b/clang/test/Sema/annotate-type.c --- a/clang/test/Sema/annotate-type.c +++ b/clang/test/Sema/annotate-type.c @@ -17,11 +17,8 @@ int *__attribute__((annotate_type("bar"))) y2; // expected-warning {{unknown attribute 'annotate_type' ignored}} // Various error cases - // FIXME: We would want to prohibit the attribute on the following two lines. - // However, Clang currently generally doesn't prohibit type-only C++11 - // attributes on declarations. This should be fixed more generally. - [[clang::annotate_type("bar")]] int *z1; - int *z2 [[clang::annotate_type("bar")]]; + [[clang::annotate_type("bar")]] int *z1; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} + int *z2 [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} [[clang::annotate_type("bar")]]; // expected-error {{'annotate_type' attribute cannot be applied to a statement}} int *[[clang::annotate_type(1)]] z3; // expected-error {{'annotate_type' attribute requires a string}} int *[[clang::annotate_type()]] z4; // expected-error {{'annotate_type' attribute takes at least 1 argument}} @@ -33,15 +30,13 @@ } // More error cases: Prohibit adding the attribute to declarations. // Different declarations hit different code paths, so they need separate tests. -// FIXME: Clang currently generally doesn't prohibit type-only C++11 -// attributes on declarations. -[[clang::annotate_type("bar")]] int *global; -void annotated_function([[clang::annotate_type("bar")]] int); -void g([[clang::annotate_type("bar")]] int); -struct [[clang::annotate_type("foo")]] S; -struct [[clang::annotate_type("foo")]] S{ - [[clang::annotate_type("foo")]] int member; - [[clang::annotate_type("foo")]] union { +[[clang::annotate_type("bar")]] int *global; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} +[[clang::annotate_type("bar")]] void annotated_function(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} +void g([[clang::annotate_type("bar")]] int); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} +struct [[clang::annotate_type("foo")]] S; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} +struct [[clang::annotate_type("foo")]] S{ // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} + [[clang::annotate_type("foo")]] int member; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} + [[clang::annotate_type("foo")]] union { // expected-error {{an attribute list cannot appear here}} int i; float f; }; diff --git a/clang/test/SemaCXX/address-space-placement.cpp b/clang/test/SemaCXX/address-space-placement.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/address-space-placement.cpp @@ -0,0 +1,32 @@ +// RUN: %clang_cc1 -fsyntax-only -fcxx-exceptions -verify %s + +// Check that we emit the correct warnings in various situations where the C++11 +// spelling of the `address_space` attribute is applied to a declaration instead +// of a type. + +void f([[clang::address_space(1)]] int* param) { // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + [[clang::address_space(1)]] int* local1; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + int* local2 [[clang::address_space(1)]]; // expected-error {{automatic variable qualified with an address space}} expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + + for ([[clang::address_space(1)]] int* p = nullptr; p; ++p) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + for (; [[clang::address_space(1)]] int* p = nullptr; ) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + while([[clang::address_space(1)]] int* p = nullptr) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + if ([[clang::address_space(1)]] int* p = nullptr) {} // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + try { + } catch([[clang::address_space(1)]] int& i) { // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + } +} + +[[clang::address_space(1)]] int* return_value(); // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + +[[clang::address_space(1)]] int global1; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} +int global2 [[clang::address_space(1)]]; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + +struct [[clang::address_space(1)]] S { // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + [[clang::address_space(1)]] int* member_function(); // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} +}; + +template +[[clang::address_space(1)]] T var_template; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} + +using void_ptr [[clang::address_space(1)]] = void *; // expected-warning {{applying attribute 'address_space' to a declaration is deprecated; apply it to the type instead}} diff --git a/clang/test/SemaCXX/annotate-type.cpp b/clang/test/SemaCXX/annotate-type.cpp --- a/clang/test/SemaCXX/annotate-type.cpp +++ b/clang/test/SemaCXX/annotate-type.cpp @@ -2,10 +2,7 @@ struct S1 { void f() [[clang::annotate_type("foo")]]; - // FIXME: We would want to prohibit the attribute in the following location. - // However, Clang currently generally doesn't prohibit type-only C++11 - // attributes on declarations. This should be fixed more generally. - [[clang::annotate_type("foo")]] void g(); + [[clang::annotate_type("foo")]] void g(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} }; template struct is_same { @@ -48,23 +45,21 @@ // More error cases: Prohibit adding the attribute to declarations. // Different declarations hit different code paths, so they need separate tests. -// FIXME: Clang currently generally doesn't prohibit type-only C++11 -// attributes on declarations. -namespace [[clang::annotate_type("foo")]] my_namespace {} -struct [[clang::annotate_type("foo")]] S3; -struct [[clang::annotate_type("foo")]] S3{ - [[clang::annotate_type("foo")]] int member; +namespace [[clang::annotate_type("foo")]] my_namespace {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} +struct [[clang::annotate_type("foo")]] S3; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} +struct [[clang::annotate_type("foo")]] S3{ // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} + [[clang::annotate_type("foo")]] int member; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} }; void f4() { - for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {} - for (; [[clang::annotate_type("foo")]] bool b = false;) {} - while ([[clang::annotate_type("foo")]] bool b = false) {} - if ([[clang::annotate_type("foo")]] bool b = false) {} + for ([[clang::annotate_type("foo")]] int i = 0; i < 42; ++i) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} + for (; [[clang::annotate_type("foo")]] bool b = false;) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} + while ([[clang::annotate_type("foo")]] bool b = false) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} + if ([[clang::annotate_type("foo")]] bool b = false) {} // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} try { - } catch ([[clang::annotate_type("foo")]] int i) { + } catch ([[clang::annotate_type("foo")]] int i) { // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} } } template -[[clang::annotate_type("foo")]] T var_template; -[[clang::annotate_type("foo")]] extern "C" int extern_c_func(); -extern "C" [[clang::annotate_type("foo")]] int extern_c_func(); +[[clang::annotate_type("foo")]] T var_template; // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} +[[clang::annotate_type("foo")]] extern "C" int extern_c_func(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} +extern "C" [[clang::annotate_type("foo")]] int extern_c_func(); // expected-error {{'annotate_type' attribute cannot be applied to a declaration}} diff --git a/clang/test/SemaOpenCL/address-spaces.cl b/clang/test/SemaOpenCL/address-spaces.cl --- a/clang/test/SemaOpenCL/address-spaces.cl +++ b/clang/test/SemaOpenCL/address-spaces.cl @@ -266,9 +266,9 @@ __attribute__((opencl_private)) private_int_t var5; // expected-warning {{multiple identical address spaces specified for type}} __attribute__((opencl_private)) private_int_t *var6; // expected-warning {{multiple identical address spaces specified for type}} #if __OPENCL_CPP_VERSION__ - [[clang::opencl_private]] __global int var7; // expected-error {{multiple address spaces specified for type}} - [[clang::opencl_private]] __global int *var8; // expected-error {{multiple address spaces specified for type}} - [[clang::opencl_private]] private_int_t var9; // expected-warning {{multiple identical address spaces specified for type}} - [[clang::opencl_private]] private_int_t *var10; // expected-warning {{multiple identical address spaces specified for type}} + __global int [[clang::opencl_private]] var7; // expected-error {{multiple address spaces specified for type}} + __global int [[clang::opencl_private]] *var8; // expected-error {{multiple address spaces specified for type}} + private_int_t [[clang::opencl_private]] var9; // expected-warning {{multiple identical address spaces specified for type}} + private_int_t [[clang::opencl_private]] *var10; // expected-warning {{multiple identical address spaces specified for type}} #endif // !__OPENCL_CPP_VERSION__ } diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3734,7 +3734,7 @@ if (!StmtSubjects.empty()) { OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, "; OS << "const Decl *D) const override {\n"; - OS << " S.Diag(AL.getLoc(), diag::err_stmt_attribute_invalid_on_decl)\n"; + OS << " S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n"; OS << " << AL << D->getLocation();\n"; OS << " return false;\n"; OS << "}\n\n";