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, 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 @@ -201,9 +201,11 @@ ParsingDeclRAIIObject ParsingRAII; public: - ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, DeclaratorContext C) - : Declarator(DS, C), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { - } + ParsingDeclarator(Parser &P, const ParsingDeclSpec &DS, + const ParsedAttributes &DeclarationAttrs, + DeclaratorContext C) + : Declarator(DS, DeclarationAttrs, C), + ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {} const ParsingDeclSpec &getDeclSpec() const { return static_cast(Declarator::getDeclSpec()); @@ -228,9 +230,10 @@ ParsingDeclRAIIObject ParsingRAII; public: - ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS) - : FieldDeclarator(DS), ParsingRAII(P, &DS.getDelayedDiagnosticPool()) { - } + ParsingFieldDeclarator(Parser &P, const ParsingDeclSpec &DS, + const ParsedAttributes &DeclarationAttrs) + : FieldDeclarator(DS, DeclarationAttrs), + ParsingRAII(P, &DS.getDelayedDiagnosticPool()) {} const ParsingDeclSpec &getDeclSpec() const { return static_cast(D.getDeclSpec()); 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; + const ParsedAttributes &DeclarationAttrs; + /// The asm label, if specified. Expr *AsmLabel; @@ -1891,7 +1893,24 @@ friend struct DeclaratorChunk; public: - Declarator(const DeclSpec &ds, DeclaratorContext C) + /// `ds` and `DeclarationAttrs` must outlive the `Declarator`. In particular, + /// take care not to pass temporary objects for these parameters. + /// + /// `DeclarationAttrs` contains [[]] attributes from the + /// attribute-specifier-seq at the beginning of a declaration, which appertain + /// to the declared entity itself. Attributes with other syntax (e.g. GNU) + /// should not be placed in this attribute list; if they occur at the + /// beginning of a declaration, they apply to the `DeclSpec` and should be + /// attached to that instead. + /// + /// 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. + Declarator(const DeclSpec &ds, const ParsedAttributes &DeclarationAttrs, + DeclaratorContext C) : DS(ds), Range(ds.getSourceRange()), Context(C), InvalidType(DS.getTypeSpecType() == DeclSpec::TST_error), GroupingParens(false), FunctionDefinition(static_cast( @@ -1899,8 +1918,13 @@ Redeclaration(false), Extension(false), ObjCIvar(false), ObjCWeakProperty(false), InlineStorageUsed(false), HasInitializer(false), Attrs(ds.getAttributePool().getFactory()), - AsmLabel(nullptr), TrailingRequiresClause(nullptr), - InventedTemplateParameterList(nullptr) {} + DeclarationAttrs(DeclarationAttrs), AsmLabel(nullptr), + TrailingRequiresClause(nullptr), + InventedTemplateParameterList(nullptr) { + assert(llvm::all_of(DeclarationAttrs, [](const ParsedAttr &AL) { + return AL.isStandardAttributeSyntax(); + })); + } ~Declarator() { clear(); @@ -2523,9 +2547,14 @@ const ParsedAttributes &getAttributes() const { return Attrs; } ParsedAttributes &getAttributes() { return Attrs; } + const ParsedAttributes &getDeclarationAttributes() const { + 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()) @@ -2607,8 +2636,10 @@ struct FieldDeclarator { Declarator D; Expr *BitfieldSize; - explicit FieldDeclarator(const DeclSpec &DS) - : D(DS, DeclaratorContext::Member), BitfieldSize(nullptr) {} + explicit FieldDeclarator(const DeclSpec &DS, + const ParsedAttributes &DeclarationAttrs) + : D(DS, DeclarationAttrs, DeclaratorContext::Member), + BitfieldSize(nullptr) {} }; /// Represents a C++11 virt-specifier-seq. 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,18 @@ bool isKnownToGCC() const; bool isSupportedByPragmaAttribute() const; + /// Returns whether a [[]] 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). + /// + /// By the standard, attributes specified before the declaration always + /// appertain to the declaration, but historically we have allowed some of + /// these attributes to slide to the decl-specifier-seq, so we need to keep + /// supporting this behavior. + /// + /// This may only be called if isStandardAttributeSyntax() returns true. + 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 +1115,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 @@ -56,7 +56,8 @@ *OwnedType = DS.isTypeSpecOwned() ? DS.getRepAsDecl() : nullptr; // Parse the abstract-declarator, if present. - Declarator DeclaratorInfo(DS, Context); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, Context); ParseDeclarator(DeclaratorInfo); if (Range) *Range = DeclaratorInfo.getSourceRange(); @@ -1750,7 +1751,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 +1763,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 +1826,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 +1844,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 +1862,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 +2018,16 @@ /// result. Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS, DeclaratorContext Context, + ParsedAttributes &Attrs, SourceLocation *DeclEnd, ForRangeInit *FRI) { // Parse the first declarator. - ParsingDeclarator D(*this, DS, Context); + // Consume all of the attributes from `Attrs` my moving them to our own local + // list. This ensures that we will not attempt to interpret them as statement + // attributes higher up the callchain. + ParsedAttributes LocalAttrs(AttrFactory); + LocalAttrs.takeAllFrom(Attrs); + ParsingDeclarator D(*this, DS, LocalAttrs, Context); ParseDeclarator(D); // Bail out if the first declarator didn't seem well-formed. @@ -4300,7 +4318,6 @@ // Parse leading attributes. ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); - DS.takeAttributesFrom(Attrs); // Parse the common specifier-qualifiers-list piece. ParseSpecifierQualifierList(DS); @@ -4308,6 +4325,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 6.7.2.1p9 : "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); @@ -4320,7 +4342,7 @@ bool FirstDeclarator = true; SourceLocation CommaLoc; while (true) { - ParsingFieldDeclarator DeclaratorInfo(*this, DS); + ParsingFieldDeclarator DeclaratorInfo(*this, DS, Attrs); DeclaratorInfo.D.setCommaLoc(CommaLoc); // Attributes are only allowed here on successive declarators. @@ -4680,7 +4702,9 @@ // declares 'enum E : int; E *p;' not 'enum E : int*; E p;'. DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS, AS, DeclSpecContext::DSC_type_specifier); - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, + DeclaratorContext::TypeName); BaseType = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); BaseRange = SourceRange(ColonLoc, DeclaratorInfo.getSourceRange().getEnd()); @@ -6597,9 +6621,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 +6925,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. @@ -6953,33 +6977,37 @@ // Just use the ParsingDeclaration "scope" of the declarator. DeclSpec DS(AttrFactory); - // Parse any C++11 attributes. - MaybeParseCXX11Attributes(DS.getAttributes()); + ParsedAttributes ArgDeclAttrs(AttrFactory); + ParsedAttributes ArgDeclSpecAttrs(AttrFactory); - // Skip any Microsoft attributes before a param. - MaybeParseMicrosoftAttributes(DS.getAttributes()); + if (FirstArgAttrs.Range.isValid()) { + // 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. + // We have already started parsing the decl-specifier sequence, so don't + // parse any parameter-declaration pieces that precede it. + ArgDeclSpecAttrs.takeAllFrom(FirstArgAttrs); + } else { + // Parse any C++11 attributes. + MaybeParseCXX11Attributes(ArgDeclAttrs); - SourceLocation DSStart = Tok.getLocation(); + // Skip any Microsoft attributes before a param. + MaybeParseMicrosoftAttributes(ArgDeclSpecAttrs); + } - // 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); + SourceLocation DSStart = Tok.getLocation(); ParseDeclarationSpecifiers(DS); - + DS.takeAttributesFrom(ArgDeclSpecAttrs); // Parse the declarator. This is "PrototypeContext" or // "LambdaExprParameterContext", because we must accept either // 'declarator' or 'abstract-declarator' here. - Declarator ParmDeclarator( - DS, DeclaratorCtx == DeclaratorContext::RequiresExpr - ? DeclaratorContext::RequiresExpr - : DeclaratorCtx == DeclaratorContext::LambdaExpr - ? DeclaratorContext::LambdaExprParameter - : DeclaratorContext::Prototype); + Declarator ParmDeclarator(DS, ArgDeclAttrs, + DeclaratorCtx == DeclaratorContext::RequiresExpr + ? DeclaratorContext::RequiresExpr + : DeclaratorCtx == DeclaratorContext::LambdaExpr + ? DeclaratorContext::LambdaExprParameter + : DeclaratorContext::Prototype); ParseDeclarator(ParmDeclarator); // Parse GNU attributes, if present. @@ -7278,7 +7306,8 @@ assert(!D.mayOmitIdentifier() && "Declarator cannot omit identifier"); SourceLocation StartBracketLoc = Tok.getLocation(); - Declarator TempDeclarator(D.getDeclSpec(), D.getContext()); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator TempDeclarator(D.getDeclSpec(), EmptyDeclAttrs, D.getContext()); while (Tok.is(tok::l_square)) { ParseBracketDeclarator(TempDeclarator); 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 @@ -354,8 +354,8 @@ getCurScope(), DS.getSourceRange().getBegin(), Lang.get(), Tok.is(tok::l_brace) ? Tok.getLocation() : SourceLocation()); - ParsedAttributes attrs(AttrFactory); - MaybeParseCXX11Attributes(attrs); + ParsedAttributes DeclAttrs(AttrFactory); + 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(); @@ -1218,7 +1218,8 @@ EndLocation = ParseDecltypeSpecifier(DS); - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, DeclaratorContext::TypeName); return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } @@ -1310,7 +1311,8 @@ DS.SetTypeSpecType(TST_typename, IdLoc, PrevSpec, DiagID, Type, Actions.getASTContext().getPrintingPolicy()); - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, DeclaratorContext::TypeName); return Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); } @@ -2676,23 +2678,21 @@ 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); - - // 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; + return ParseOpenMPDeclarativeDirectiveWithExtDecl(AS, DeclAttrs); - MaybeParseMicrosoftAttributes(attrs); + // 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; if (Tok.is(tok::kw_using)) { // Eat 'using'. @@ -2713,16 +2713,20 @@ 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); } + ParsedAttributes DeclSpecAttrs(AttrFactory); + MaybeParseMicrosoftAttributes(DeclSpecAttrs); + // Hold late-parsed attributes so we can attach a Decl to them later. LateParsedAttrList CommonLateParsedAttrs; // decl-specifier-seq: // Parse the common declaration-specifiers piece. ParsingDeclSpec DS(*this, TemplateDiags); - DS.takeAttributesFrom(attrs); + DS.takeAttributesFrom(DeclSpecAttrs); + if (MalformedTypeSpec) DS.SetTypeSpecError(); @@ -2773,7 +2777,8 @@ return Actions.ConvertDeclToDeclGroup(TheDecl); } - ParsingDeclarator DeclaratorInfo(*this, DS, DeclaratorContext::Member); + ParsingDeclarator DeclaratorInfo(*this, DS, DeclAttrs, + DeclaratorContext::Member); if (TemplateInfo.TemplateParams) DeclaratorInfo.setTemplateParameterLists(TemplateParams); VirtSpecifiers VS; diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp --- a/clang/lib/Parse/ParseExpr.cpp +++ b/clang/lib/Parse/ParseExpr.cpp @@ -1212,7 +1212,9 @@ DS.SetTypeSpecType(TST_typename, ILoc, PrevSpec, DiagID, Typ, Actions.getASTContext().getPrintingPolicy()); - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, + DeclaratorContext::TypeName); TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); if (Ty.isInvalid()) @@ -1490,7 +1492,9 @@ PrevSpec, DiagID, Type, Actions.getASTContext().getPrintingPolicy()); - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, + DeclaratorContext::TypeName); TypeResult Ty = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); if (Ty.isInvalid()) break; @@ -2296,7 +2300,9 @@ if (isTypeIdUnambiguously()) { DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, + DeclaratorContext::TypeName); ParseDeclarator(DeclaratorInfo); SourceLocation LParenLoc = PP.getLocForEndOfToken(OpTok.getLocation()); @@ -2958,7 +2964,8 @@ // Parse the type declarator. DeclSpec DS(AttrFactory); ParseSpecifierQualifierList(DS); - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, DeclaratorContext::TypeName); ParseDeclarator(DeclaratorInfo); // If our type is followed by an identifier and either ':' or ']', then @@ -3493,7 +3500,9 @@ ParseSpecifierQualifierList(DS); // Parse the block-declarator. - Declarator DeclaratorInfo(DS, DeclaratorContext::BlockLiteral); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, + DeclaratorContext::BlockLiteral); DeclaratorInfo.setFunctionDefinitionKind(FunctionDefinitionKind::Definition); ParseDeclarator(DeclaratorInfo); @@ -3532,7 +3541,8 @@ // Parse the return type if present. DeclSpec DS(AttrFactory); - Declarator ParamInfo(DS, DeclaratorContext::BlockLiteral); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator ParamInfo(DS, EmptyDeclAttrs, DeclaratorContext::BlockLiteral); ParamInfo.setFunctionDefinitionKind(FunctionDefinitionKind::Definition); // FIXME: Since the return type isn't actually parsed, it can't be used to // fill ParamInfo with an initial valid range, so do it manually. 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 @@ -1248,7 +1248,8 @@ // Parse lambda-declarator[opt]. DeclSpec DS(AttrFactory); - Declarator D(DS, DeclaratorContext::LambdaExpr); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator D(DS, EmptyDeclAttrs, DeclaratorContext::LambdaExpr); TemplateParameterDepthRAII CurTemplateDepthTracker(TemplateParameterDepth); Actions.PushLambdaScope(); @@ -1523,7 +1524,8 @@ ParseSpecifierQualifierList(DS); // Parse the abstract-declarator, if present. - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, DeclaratorContext::TypeName); ParseDeclarator(DeclaratorInfo); SourceLocation RAngleBracketLoc = Tok.getLocation(); @@ -1849,7 +1851,9 @@ /// In C++1z onwards, the type specifier can also be a template-name. ExprResult Parser::ParseCXXTypeConstructExpression(const DeclSpec &DS) { - Declarator DeclaratorInfo(DS, DeclaratorContext::FunctionalCast); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, + DeclaratorContext::FunctionalCast); ParsedType TypeRep = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo).get(); assert((Tok.is(tok::l_paren) || @@ -2048,9 +2052,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 +2067,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 +2086,10 @@ // type-specifier-seq DeclSpec DS(AttrFactory); - DS.takeAttributesFrom(attrs); ParseSpecifierQualifierList(DS, AS_none, DeclSpecContext::DSC_condition); // declarator - Declarator DeclaratorInfo(DS, DeclaratorContext::Condition); + Declarator DeclaratorInfo(DS, attrs, DeclaratorContext::Condition); ParseDeclarator(DeclaratorInfo); // simple-asm-expr[opt] @@ -2736,7 +2742,8 @@ // Parse the conversion-declarator, which is merely a sequence of // ptr-operators. - Declarator D(DS, DeclaratorContext::ConversionId); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator D(DS, EmptyDeclAttrs, DeclaratorContext::ConversionId); ParseDeclaratorInternal(D, /*DirectDeclParser=*/nullptr); // Finish up the type. @@ -3094,7 +3101,8 @@ SourceRange TypeIdParens; DeclSpec DS(AttrFactory); - Declarator DeclaratorInfo(DS, DeclaratorContext::CXXNew); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, DeclaratorContext::CXXNew); if (Tok.is(tok::l_paren)) { // If it turns out to be a placement, we change the type location. BalancedDelimiterTracker T(*this, tok::l_paren); @@ -3945,7 +3953,8 @@ if (ParseAs >= CompoundLiteral) { // Parse the type declarator. DeclSpec DS(AttrFactory); - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, DeclaratorContext::TypeName); { ColonProtectionRAIIObject InnerColonProtection(*this); ParseSpecifierQualifierList(DS); @@ -4023,7 +4032,8 @@ ParseSpecifierQualifierList(DS); // Parse the abstract-declarator, if present. - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, DeclaratorContext::TypeName); ParseDeclarator(DeclaratorInfo); if (ExpectAndConsume(tok::comma)) { 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 @@ -650,19 +650,21 @@ if (Tok.is(tok::r_brace)) break; - ParsedAttributes attrs(AttrFactory); + ParsedAttributes EmptyAttrs(AttrFactory); // Since we call ParseDeclarationOrFunctionDefinition() instead of // ParseExternalDeclaration() below (so that this doesn't parse nested // @interfaces), this needs to duplicate some code from the latter. if (Tok.isOneOf(tok::kw_static_assert, tok::kw__Static_assert)) { SourceLocation DeclEnd; - allTUVariables.push_back( - ParseDeclaration(DeclaratorContext::File, DeclEnd, attrs)); + ParsedAttributes EmptyDeclSpecAttrs(AttrFactory); + allTUVariables.push_back(ParseDeclaration( + DeclaratorContext::File, DeclEnd, EmptyAttrs, EmptyDeclSpecAttrs)); continue; } - allTUVariables.push_back(ParseDeclarationOrFunctionDefinition(attrs)); + allTUVariables.push_back( + ParseDeclarationOrFunctionDefinition(EmptyAttrs)); continue; } @@ -1225,6 +1227,10 @@ /// declarator and add them to the given list. static void takeDeclAttributes(ParsedAttributes &attrs, Declarator &D) { + // This gets called only from Parser::ParseObjCTypeName(), and that should + // never add declaration attributes to the Declarator. + assert(D.getDeclarationAttributes().empty()); + // First, take ownership of all attributes. attrs.getPool().takeAllFrom(D.getAttributePool()); attrs.getPool().takeAllFrom(D.getDeclSpec().getAttributePool()); @@ -1268,7 +1274,8 @@ if (context == DeclaratorContext::ObjCResult) dsContext = DeclSpecContext::DSC_objc_method_result; ParseSpecifierQualifierList(declSpec, AS_none, dsContext); - Declarator declarator(declSpec, context); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator declarator(declSpec, EmptyDeclAttrs, context); ParseDeclarator(declarator); // If that's not invalid, extract a type. @@ -1487,7 +1494,8 @@ DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); // Parse the declarator. - Declarator ParmDecl(DS, DeclaratorContext::Prototype); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator ParmDecl(DS, EmptyDeclAttrs, DeclaratorContext::Prototype); ParseDeclarator(ParmDecl); IdentifierInfo *ParmII = ParmDecl.getIdentifier(); Decl *Param = Actions.ActOnParamDeclarator(getCurScope(), ParmDecl); @@ -1693,7 +1701,8 @@ typeArg, Actions.getASTContext().getPrintingPolicy()); // Form a declarator to turn this into a type. - Declarator D(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator D(DS, EmptyDeclAttrs, DeclaratorContext::TypeName); TypeResult fullTypeArg = Actions.ActOnTypeName(getCurScope(), D); if (fullTypeArg.isUsable()) { typeArgs.push_back(fullTypeArg.get()); @@ -2538,7 +2547,8 @@ if (Tok.isNot(tok::ellipsis)) { DeclSpec DS(AttrFactory); ParseDeclarationSpecifiers(DS); - Declarator ParmDecl(DS, DeclaratorContext::ObjCCatch); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator ParmDecl(DS, EmptyDeclAttrs, DeclaratorContext::ObjCCatch); ParseDeclarator(ParmDecl); // Inform the actions module about the declarator, so it @@ -2954,7 +2964,8 @@ // We have a class message. Turn the simple-type-specifier or // typename-specifier we parsed into a type and parse the // remainder of the class message. - Declarator DeclaratorInfo(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, DeclaratorContext::TypeName); TypeResult Type = Actions.ActOnTypeName(getCurScope(), DeclaratorInfo); if (Type.isInvalid()) return true; diff --git a/clang/lib/Parse/ParseOpenMP.cpp b/clang/lib/Parse/ParseOpenMP.cpp --- a/clang/lib/Parse/ParseOpenMP.cpp +++ b/clang/lib/Parse/ParseOpenMP.cpp @@ -639,7 +639,8 @@ // Parse the declarator. DeclaratorContext Context = DeclaratorContext::Prototype; - Declarator DeclaratorInfo(DS, Context); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator DeclaratorInfo(DS, EmptyDeclAttrs, Context); ParseDeclarator(DeclaratorInfo); Range = DeclaratorInfo.getSourceRange(); if (DeclaratorInfo.getIdentifier() == nullptr) { 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 @@ -13,6 +13,7 @@ #include "clang/AST/PrettyDeclStackTrace.h" #include "clang/Basic/Attributes.h" +#include "clang/Basic/DiagnosticSema.h" #include "clang/Basic/PrettyStackTrace.h" #include "clang/Parse/LoopHint.h" #include "clang/Parse/Parser.h" @@ -105,15 +106,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 +165,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 +192,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 +227,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 +263,7 @@ case tok::kw___attribute: { GNUAttributeLoc = Tok.getLocation(); - ParseGNUAttributes(Attrs); + ParseGNUAttributes(GNUAttrs); goto Retry; } @@ -297,7 +315,15 @@ break; case tok::kw_asm: { - ProhibitAttributes(Attrs); + if (getLangOpts().CPlusPlus) { + for (const ParsedAttr &AL : CXX11Attrs) { + Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL; + } + // Prevent these from being interpreted as statement attributes later on. + CXX11Attrs.clear(); + } else + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); bool msAsm = false; Res = ParseAsmStatement(msAsm); Res = Actions.ActOnFinishFullStmt(Res.get()); @@ -308,7 +334,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 +345,8 @@ return ParseCXXTryBlock(); case tok::kw___try: - ProhibitAttributes(Attrs); // TODO: is it correct? + ProhibitAttributes(CXX11Attrs); + ProhibitAttributes(GNUAttrs); return ParseSEHTryBlock(); case tok::kw___leave: @@ -327,55 +355,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 +421,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 +705,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 +1176,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 +2024,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 +2397,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 +2635,11 @@ MaybeParseCXX11Attributes(Attributes); DeclSpec DS(AttrFactory); - DS.takeAttributesFrom(Attributes); if (ParseCXXTypeSpecifierSeq(DS)) return StmtError(); - Declarator ExDecl(DS, DeclaratorContext::CXXCatch); + Declarator ExDecl(DS, Attributes, DeclaratorContext::CXXCatch); 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); + ParsingDeclarator DeclaratorInfo(*this, DS, prefixAttrs, + (DeclaratorContext)Context); if (TemplateInfo.TemplateParams) DeclaratorInfo.setTemplateParameterLists(*TemplateInfo.TemplateParams); @@ -666,7 +665,8 @@ // probably meant to write the type of a NTTP. DeclSpec DS(getAttrFactory()); DS.SetTypeSpecError(); - Declarator D(DS, DeclaratorContext::TemplateParam); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator D(DS, EmptyDeclAttrs, DeclaratorContext::TemplateParam); D.SetIdentifier(nullptr, Tok.getLocation()); D.setInvalidType(true); NamedDecl *ErrorParam = Actions.ActOnNonTypeTemplateParameter( @@ -990,7 +990,8 @@ DeclSpecContext::DSC_template_param); // Parse this as a typename. - Declarator ParamDecl(DS, DeclaratorContext::TemplateParam); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator ParamDecl(DS, EmptyDeclAttrs, DeclaratorContext::TemplateParam); ParseDeclarator(ParamDecl); if (DS.getTypeSpecType() == DeclSpec::TST_unspecified) { Diag(Tok.getLocation(), diag::err_expected_template_parameter); 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 EmptyDeclSpecAttrs(AttrFactory); + return ParseDeclaration(DeclaratorContext::File, DeclEnd, Attrs, + EmptyDeclSpecAttrs); } 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,12 @@ if (getLangOpts().CPlusPlus && isTokenStringLiteral() && DS.getStorageClassSpec() == DeclSpec::SCS_extern && DS.getParsedSpecifiers() == DeclSpec::PQ_StorageClassSpecifier) { + ProhibitAttributes(Attrs); Decl *TheDecl = ParseLinkage(DS, DeclaratorContext::File); return Actions.ConvertDeclToDeclGroup(TheDecl); } - return ParseDeclGroup(DS, DeclaratorContext::File); + return ParseDeclGroup(DS, DeclaratorContext::File, Attrs); } Parser::DeclGroupPtrTy Parser::ParseDeclarationOrFunctionDefinition( @@ -1471,7 +1482,9 @@ } // Parse the first declarator attached to this declspec. - Declarator ParmDeclarator(DS, DeclaratorContext::KNRTypeList); + ParsedAttributes EmptyDeclAttrs(AttrFactory); + Declarator ParmDeclarator(DS, EmptyDeclAttrs, + DeclaratorContext::KNRTypeList); ParseDeclarator(ParmDeclarator); // Handle the full declarator list. 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,42 @@ return getInfo().IsSupportedByPragmaAttribute; } +bool ParsedAttr::slidesFromDeclToDeclSpec() const { + assert(isStandardAttributeSyntax()); + + // We have historically allowed some type 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. + // + // Note: No new entries should be added to this list. Entries should be + // removed from this list after a suitable deprecation period, provided that + // there are no compatibility considerations with other compilers. If + // possible, we would like this list to go away entirely. + 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 +301,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 @@ -5488,7 +5488,8 @@ Diag(DS.getBeginLoc(), diag::ext_no_declarators) << DS.getSourceRange(); // Mock up a declarator. - Declarator Dc(DS, DeclaratorContext::Member); + ParsedAttributes EmptyDeclAttrs(DS.getAttributePool().getFactory()); + Declarator Dc(DS, EmptyDeclAttrs, DeclaratorContext::Member); TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); assert(TInfo && "couldn't build declarator info for anonymous struct/union"); @@ -5585,7 +5586,8 @@ assert(Record && "expected a record!"); // Mock up a declarator. - Declarator Dc(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(DS.getAttributePool().getFactory()); + Declarator Dc(DS, EmptyDeclAttrs, DeclaratorContext::TypeName); TypeSourceInfo *TInfo = GetTypeForDeclarator(Dc, S); assert(TInfo && "couldn't build declarator info for anonymous struct"); @@ -7027,7 +7029,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 @@ -13348,7 +13351,8 @@ DS.SetTypeSpecType(DeclSpec::TST_auto, IdentLoc, PrevSpec, DiagID, getPrintingPolicy()); - Declarator D(DS, DeclaratorContext::ForInit); + ParsedAttributes EmptyDeclAttrs(DS.getAttributePool().getFactory()); + Declarator D(DS, EmptyDeclAttrs, DeclaratorContext::ForInit); D.SetIdentifier(Ident, IdentLoc); D.takeAttributes(Attrs); @@ -14336,7 +14340,8 @@ // Use the identifier location for the type source range. DS.SetRangeStart(FTI.Params[i].IdentLoc); DS.SetRangeEnd(FTI.Params[i].IdentLoc); - Declarator ParamD(DS, DeclaratorContext::KNRTypeList); + ParsedAttributes EmptyDeclAttrs(DS.getAttributePool().getFactory()); + Declarator ParamD(DS, EmptyDeclAttrs, DeclaratorContext::KNRTypeList); ParamD.SetIdentifier(FTI.Params[i].Ident, FTI.Params[i].IdentLoc); FTI.Params[i].Param = ActOnParamDeclarator(S, ParamD); } @@ -15366,7 +15371,8 @@ (void)Error; // Silence warning. assert(!Error && "Error setting up implicit decl!"); SourceLocation NoLoc; - Declarator D(DS, DeclaratorContext::Block); + ParsedAttributes EmptyDeclAttrs(attrFactory); + Declarator D(DS, EmptyDeclAttrs, DeclaratorContext::Block); D.AddTypeInfo(DeclaratorChunk::getFunction(/*HasProto=*/false, /*IsAmbiguous=*/false, /*LParenLoc=*/NoLoc, 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,19 @@ /// 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) + // We intentionally check the attribute syntax directly instead of using + // ParsedAttr::isCXX11Attribute() as the latter includes the alignas + // attribute. The alignas attribute is a declaration attribute but can appear + // on the `DeclSpec`, so we want to let it through here. + if (AL.getSyntax() == ParsedAttr::AS_CXX11 && !Options.IncludeCXX11Attributes) return; // Unknown attributes are automatically warned on. Target-specific attributes @@ -8353,14 +8357,46 @@ 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.isStandardAttributeSyntax()) { + // Non-[[]] type attributes are handled in processTypeAttrs(); silently + // move on. + break; + } + + // According to the C and C++ standards, we should never see a + // [[]] type attribute on a declaration. However, we have in the past + // allowed some type attributes to "slide" to the `DeclSpec`, so we need + // to continue to support this legacy behavior. We only do this, however, + // if + // - we actually have a `DeclSpec`, i.e. if we're looking at a + // `DeclaratorDecl`, or + // - we are looking at an alias-declaration, where historically we have + // allowed type attributes after the identifier to slide to the type. + if (AL.slidesFromDeclToDeclSpec() && + (clang::isa(D) || clang::isa(D))) { + // Suggest moving the attribute to the type instead, but only for our + // own vendor attributes; moving other vendors' attributes might hurt + // portability. + if (AL.isClangScope()) { + S.Diag(AL.getLoc(), diag::warn_type_attribute_deprecated_on_decl) + << AL << D->getLocation(); + } + + // Allow this type attribute to be handled in processTypeAttrs(); + // 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 +9040,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 +9135,8 @@ AccessSpecDecl *ASDecl, const ParsedAttributesView &AttrList) { for (const ParsedAttr &AL : AttrList) { if (AL.getKind() == ParsedAttr::AT_Annotate) { - ProcessDeclAttribute(*this, nullptr, ASDecl, AL, AL.isCXX11Attribute()); + ProcessDeclAttribute(*this, nullptr, ASDecl, AL, + ProcessDeclAttributeOptions()); } else { Diag(AL.getLoc(), diag::err_only_annotate_after_access_spec); return true; @@ -9133,6 +9170,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()); @@ -9240,17 +9278,37 @@ /// it, apply them to D. This is a bit tricky because PD can have attributes /// specified in many different places, and we need to find and apply them all. void Sema::ProcessDeclAttributes(Scope *S, Decl *D, const Declarator &PD) { + // Ordering of attributes can be important, so we take care to process + // attributes in the order in which they appeared in the source code. + + // First, process attributes that appeared on the declaration itself (but + // only if they don't have the legacy behavior of "sliding" to the DeclSepc). + ParsedAttributesView NonSlidingAttrs; + for (ParsedAttr &AL : PD.getDeclarationAttributes()) { + if (!AL.slidesFromDeclToDeclSpec()) { + NonSlidingAttrs.addAtEnd(&AL); + } + } + ProcessDeclAttributeList(S, D, NonSlidingAttrs); + // 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() + .WithIncludeCXX11Attributes(false) + .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. ProcessDeclAttributeList(S, D, PD.getAttributes()); diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -16848,7 +16848,8 @@ // Try to convert the decl specifier to a type. This works for // friend templates because ActOnTag never produces a ClassTemplateDecl // for a TUK_Friend. - Declarator TheDeclarator(DS, DeclaratorContext::Member); + ParsedAttributes EmptyDeclAttrs(DS.getAttributePool().getFactory()); + Declarator TheDeclarator(DS, EmptyDeclAttrs, DeclaratorContext::Member); TypeSourceInfo *TSI = GetTypeForDeclarator(TheDeclarator, S); QualType T = TSI->getType(); if (TheDeclarator.isInvalidType()) diff --git a/clang/lib/Sema/SemaDeclObjC.cpp b/clang/lib/Sema/SemaDeclObjC.cpp --- a/clang/lib/Sema/SemaDeclObjC.cpp +++ b/clang/lib/Sema/SemaDeclObjC.cpp @@ -1586,7 +1586,8 @@ DS.SetRangeEnd(loc); // Form the declarator. - Declarator D(DS, DeclaratorContext::TypeName); + ParsedAttributes EmptyDeclAttrs(attrFactory); + Declarator D(DS, EmptyDeclAttrs, DeclaratorContext::TypeName); // If we have a typedef of an Objective-C class type that is missing a '*', // add the '*'. 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 @@ -640,15 +640,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,8 +650,10 @@ 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, ParsedAttr &attr, QualType &declSpecType) { @@ -677,7 +670,7 @@ 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,11 +679,11 @@ /// 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, 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. @@ -1804,8 +1797,36 @@ // 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; + } + } + } + // During this call to processTypeAttrs(), + // TypeProcessingState::getCurrentAttributes() will erroneously return a + // reference to the DeclSpec attributes, rather than the declaration + // attributes. However, this doesn't matter, as getCurrentAttributes() + // is only called when distributing attributes from one attribute list + // to another. Declaration attributes are always C++11 attributes, and these + // are never distributed. + processTypeAttrs(state, Result, TAL_DeclSpec, SlidingAttrs); processTypeAttrs(state, Result, TAL_DeclSpec, DS.getAttributes()); + } // Apply const/volatile/restrict qualifiers to T. if (unsigned TypeQuals = DS.getTypeQualifiers()) { @@ -3412,8 +3433,10 @@ break; } - if (!D.getAttributes().empty()) - distributeTypeAttrsFromDeclarator(state, T); + // Note: We don't need to distribute declaration attributes (i.e. + // D.getDeclarationAttributes()) because those are always C++11 attributes, + // and those don't get distributed. + distributeTypeAttrsFromDeclarator(state, 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 +4735,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 +5306,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 +5722,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. @@ -8237,11 +8270,14 @@ continue; } } else if (TAL != TAL_DeclChunk && !isAddressSpaceKind(attr) && - attr.getKind() != ParsedAttr::AT_AnnotateType) { + attr.getKind() != ParsedAttr::AT_AnnotateType && + attr.getKind() != ParsedAttr::UnknownAttribute) { // Otherwise, only consider type processing for a C++11 attribute if // it's actually been applied to a type. - // We also allow C++11 address_space and annotate_type and - // OpenCL language address space attributes to pass through. + // We also allow some attributes to pass through generally: + // - C++11 address_space and OpenCL language address space attributes + // - annotate_type + // - Unknown attributes (for generating warnings) continue; } } @@ -8259,10 +8295,15 @@ break; case ParsedAttr::UnknownAttribute: - if (attr.isStandardAttributeSyntax() && TAL == TAL_DeclChunk) + if (attr.isStandardAttributeSyntax() && + (TAL == TAL_DeclChunk || TAL == TAL_DeclSpec)) { state.getSema().Diag(attr.getLoc(), diag::warn_unknown_attribute_ignored) << attr << attr.getRange(); + // Mark the attribute as invalid so we don't emit the same diagnostic + // multiple times. + attr.setInvalid(); + } break; case ParsedAttr::IgnoredAttribute: diff --git a/clang/test/Parser/MicrosoftExtensions.cpp b/clang/test/Parser/MicrosoftExtensions.cpp --- a/clang/test/Parser/MicrosoftExtensions.cpp +++ b/clang/test/Parser/MicrosoftExtensions.cpp @@ -57,6 +57,14 @@ struct_with_uuid { }; struct struct_without_uuid { }; +struct base { + int a; +}; +struct derived : base { + // Can't apply a UUID to a using declaration. + [uuid("000000A0-0000-0000-C000-00000000004A")] using base::a; // expected-error {{expected member name}} +}; + struct __declspec(uuid("000000A0-0000-0000-C000-000000000049")) struct_with_uuid2; diff --git a/clang/test/Parser/asm.c b/clang/test/Parser/asm.c --- a/clang/test/Parser/asm.c +++ b/clang/test/Parser/asm.c @@ -1,4 +1,4 @@ -// RUN: %clang_cc1 -fsyntax-only -verify %s +// RUN: %clang_cc1 -fsyntax-only -fdouble-square-bracket-attributes -verify %s #if !__has_extension(gnu_asm) #error Extension 'gnu_asm' should be available by default @@ -12,6 +12,9 @@ void f2(void) { asm("foo" : "=r" (a)); // expected-error {{use of undeclared identifier 'a'}} asm("foo" : : "r" (b)); // expected-error {{use of undeclared identifier 'b'}} + + // C does not allow attribute lists before asm blocks. + [[]] asm(""); // expected-error {{an attribute list cannot appear here}} } void a(void) __asm__(""); // expected-error {{cannot use an empty string literal in 'asm'}} diff --git a/clang/test/Parser/asm.cpp b/clang/test/Parser/asm.cpp --- a/clang/test/Parser/asm.cpp +++ b/clang/test/Parser/asm.cpp @@ -7,3 +7,8 @@ int foo5 asm (U"bar5"); // expected-error {{cannot use unicode string literal in 'asm'}} int foo6 asm ("bar6"_x); // expected-error {{string literal with user-defined suffix cannot be used here}} int foo6 asm ("" L"bar7"); // expected-error {{cannot use wide string literal in 'asm'}} + +void f() { + [[]] asm(""); + [[gnu::deprecated]] asm(""); // expected-warning {{'deprecated' attribute ignored}} +} diff --git a/clang/test/Parser/c2x-attributes.c b/clang/test/Parser/c2x-attributes.c --- a/clang/test/Parser/c2x-attributes.c +++ b/clang/test/Parser/c2x-attributes.c @@ -34,6 +34,8 @@ int [[]] : 0; // OK, attribute applies to the type. int p, [[]] : 0; // expected-error {{an attribute list cannot appear here}} int q, [[]] r; // expected-error {{an attribute list cannot appear here}} + [[]] int; // expected-error {{an attribute list cannot appear here}} \ + // expected-warning {{declaration does not declare anything}} }; [[]] struct S2 { int a; }; // expected-error {{misplaced attributes}} diff --git a/clang/test/Parser/cxx0x-attributes.cpp b/clang/test/Parser/cxx0x-attributes.cpp --- a/clang/test/Parser/cxx0x-attributes.cpp +++ b/clang/test/Parser/cxx0x-attributes.cpp @@ -126,6 +126,7 @@ void const_after_attr () [[]] const; // expected-error {{expected ';'}} }; extern "C++" [[]] { } // expected-error {{an attribute list cannot appear here}} +[[]] extern "C++" { } // expected-error {{an attribute list cannot appear here}} [[]] template void before_template_attr (); // expected-error {{an attribute list cannot appear here}} [[]] namespace ns { int i; } // expected-error {{an attribute list cannot appear here}} expected-note {{declared here}} [[]] static_assert(true, ""); //expected-error {{an attribute list cannot appear here}} @@ -421,3 +422,26 @@ // prefered "protected" vendor namespace. We support __clang__ only for // people expecting it to behave the same as __gnu__. [[__clang__::annotate("test")]] void annotate3(); // expected-warning {{'__clang__' is a predefined macro name, not an attribute scope specifier; did you mean '_Clang' instead?}} + +// Check ordering: C++11 attributes must appear before GNU attributes. +class Ordering { + void f1( + int ([[]] __attribute__(()) int n) + ) { + } + + void f2( + int (*)([[]] __attribute__(()) int n) + ) { + } + + void f3( + int (__attribute__(()) [[]] int n) // expected-error {{an attribute list cannot appear here}} + ) { + } + + void f4( + int (*)(__attribute__(()) [[]] int n) // expected-error {{an attribute list cannot appear here}} + ) { + } +}; 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,35 @@ +// 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-error {{'address_space' attribute cannot be applied to a declaration}} + [[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}} + +namespace N {} +[[clang::address_space(1)]] using namespace N; // expected-error {{'address_space' attribute cannot be applied to a declaration}} 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 {{an attribute list cannot appear here}} +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";