diff --git a/clang/examples/Attribute/Attribute.cpp b/clang/examples/Attribute/Attribute.cpp index 24b95dde4e5592..008da2e18e44f2 100644 --- a/clang/examples/Attribute/Attribute.cpp +++ b/clang/examples/Attribute/Attribute.cpp @@ -43,7 +43,7 @@ struct ExampleAttrInfo : public ParsedAttrInfo { // This attribute appertains to functions only. if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << Attr << "functions"; + << Attr << Attr.isRegularKeywordAttribute() << "functions"; return false; } return true; diff --git a/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp b/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp index 21460e4f6bd066..12d4c311586e6f 100644 --- a/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp +++ b/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp @@ -169,7 +169,7 @@ struct CallSuperAttrInfo : public ParsedAttrInfo { const auto *TheMethod = dyn_cast_or_null(D); if (!TheMethod || !TheMethod->isVirtual()) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << Attr << "virtual functions"; + << Attr << Attr.isRegularKeywordAttribute() << "virtual functions"; return false; } MarkedMethods.insert(TheMethod); diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td index 42d8a0abfbceb8..eb1649cc238a5e 100644 --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -121,7 +121,7 @@ def note_pragma_entered_here : Note<"#pragma entered here">; def note_decl_hiding_tag_type : Note< "%1 %0 is hidden by a non-type declaration of %0 here">; def err_attribute_not_type_attr : Error< - "%0 attribute cannot be applied to types">; + "%0%select{ attribute|}1 cannot be applied to types">; def err_enum_template : Error<"enumeration cannot be a template">; def warn_cxx20_compat_consteval : Warning< @@ -175,6 +175,8 @@ def warn_unknown_attribute_ignored : Warning< "unknown attribute %0 ignored">, InGroup; def warn_attribute_ignored : Warning<"%0 attribute ignored">, InGroup; +def err_keyword_not_supported_on_target : Error< + "%0 is not supported on this target">; def err_use_of_tag_name_without_tag : Error< "must use '%1' tag to refer to type %0%select{| in this scope}2">; diff --git a/clang/include/clang/Basic/DiagnosticParseKinds.td b/clang/include/clang/Basic/DiagnosticParseKinds.td index 5d5048a7d2c04e..d015628db7f23d 100644 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -733,10 +733,12 @@ def ext_using_attribute_ns : ExtWarn< def err_using_attribute_ns_conflict : Error< "attribute with scope specifier cannot follow default scope specifier">; def err_attributes_not_allowed : Error<"an attribute list cannot appear here">; +def err_keyword_not_allowed : Error<"%0 cannot appear here">; def ext_cxx11_attr_placement : ExtWarn< - "ISO C++ does not allow an attribute list to appear here">, + "ISO C++ does not allow %select{an attribute list|%0}1 to appear here">, InGroup>; def err_attributes_misplaced : Error<"misplaced attributes; expected attributes here">; +def err_keyword_misplaced : Error<"misplaced %0; expected %0 here">; def err_l_square_l_square_not_attribute : Error< "C++11 only allows consecutive left square brackets when " "introducing an attribute">; @@ -1014,14 +1016,15 @@ def err_lambda_capture_multiple_ellipses : Error< def err_capture_default_first : Error< "capture default must be first">; def ext_decl_attrs_on_lambda : ExtWarn< - "an attribute specifier sequence in this position is a C++23 extension">, - InGroup; + "%select{an attribute specifier sequence|%0}1 in this position " + "is a C++23 extension">, InGroup; def ext_lambda_missing_parens : ExtWarn< "lambda without a parameter clause is a C++23 extension">, InGroup; def warn_cxx20_compat_decl_attrs_on_lambda : Warning< - "an attribute specifier sequence in this position is incompatible with C++ " - "standards before C++23">, InGroup, DefaultIgnore; + "%select{an attribute specifier sequence|%1}0 in this position " + "is incompatible with C++ standards before C++23">, + InGroup, DefaultIgnore; // C++17 lambda expressions def err_expected_star_this_capture : Error< @@ -1582,8 +1585,12 @@ def err_module_expected_ident : Error< "expected a module name after '%select{module|import}0'">; def err_attribute_not_module_attr : Error< "%0 attribute cannot be applied to a module">; +def err_keyword_not_module_attr : Error< + "%0 cannot be applied to a module">; def err_attribute_not_import_attr : Error< "%0 attribute cannot be applied to a module import">; +def err_keyword_not_import_attr : Error< + "%0 cannot be applied to a module import">; def err_module_expected_semi : Error< "expected ';' after module name">; def err_global_module_introducer_not_at_start : Error< diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index 3edffbe1902731..4847509ae1ec39 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3022,7 +3022,7 @@ def err_musttail_no_variadic : Error< def err_nsobject_attribute : Error< "'NSObject' attribute is for pointer types only">; def err_attributes_are_not_compatible : Error< - "%0 and %1 attributes are not compatible">; + "%0 and %1%select{ attributes|}2 are not compatible">; def err_attribute_invalid_argument : Error< "%select{a reference type|an array type|a non-vector or " "non-vectorizable scalar type}0 is an invalid argument to attribute %1">; @@ -3430,9 +3430,9 @@ def warn_attribute_has_no_effect_on_compile_time_if : Warning< def note_attribute_has_no_effect_on_compile_time_if_here : Note< "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">; + "%0%select{ attribute|}1 cannot be applied to a statement">; def err_attribute_invalid_on_decl : Error< - "%0 attribute cannot be applied to a declaration">; + "%0%select{ attribute|}1 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; @@ -3440,6 +3440,10 @@ def warn_declspec_attribute_ignored : Warning< "attribute %0 is ignored, place it after " "\"%select{class|struct|interface|union|enum|enum class|enum struct}1\" to apply attribute to " "type declaration">, InGroup; +def err_declspec_keyword_has_no_effect : Error< + "%0 cannot appear here, place it after " + "\"%select{class|struct|interface|union|enum}1\" to apply it to the " + "type declaration">; def warn_attribute_precede_definition : Warning< "attribute declaration must precede definition">, InGroup; @@ -3538,11 +3542,11 @@ def err_attribute_weakref_without_alias : Error< def err_alias_not_supported_on_darwin : Error < "aliases are not supported on darwin">; def warn_attribute_wrong_decl_type_str : Warning< - "%0 attribute only applies to %1">, InGroup; + "%0%select{ attribute|}1 only applies to %2">, InGroup; def err_attribute_wrong_decl_type_str : Error< warn_attribute_wrong_decl_type_str.Summary>; def warn_attribute_wrong_decl_type : Warning< - "%0 attribute only applies to %select{" + "%0%select{ attribute|}1 only applies to %select{" "functions" "|unions" "|variables and functions" @@ -3555,13 +3559,15 @@ def warn_attribute_wrong_decl_type : Warning< "|types and namespaces" "|variables, functions and classes" "|kernel functions" - "|non-K&R-style functions}1">, + "|non-K&R-style functions}2">, InGroup; def err_attribute_wrong_decl_type : Error; def warn_type_attribute_wrong_type : Warning< "'%0' only applies to %select{function|pointer|" "Objective-C object or block pointer}1 types; type here is %2">, InGroup; +def err_type_attribute_wrong_type : Error< + warn_type_attribute_wrong_type.Summary>; def warn_incomplete_encoded_type : Warning< "encoding of %0 type is incomplete because %1 component has unknown encoding">, InGroup>; @@ -3612,7 +3618,7 @@ def err_invalid_pcs : Error<"invalid PCS type">; def warn_attribute_not_on_decl : Warning< "%0 attribute ignored when parsing type">, InGroup; def err_base_specifier_attribute : Error< - "%0 attribute cannot be applied to a base specifier">; + "%0%select{ attribute|}1 cannot be applied to a base specifier">; def warn_declspec_allocator_nonpointer : Warning< "ignoring __declspec(allocator) because the function return type %0 is not " "a pointer or reference type">, InGroup; diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h index 43ea50a71f744b..992d92c990e11c 100644 --- a/clang/include/clang/Parse/Parser.h +++ b/clang/include/clang/Parse/Parser.h @@ -2691,6 +2691,18 @@ class Parser : public CodeCompletionHandler { return LO.DoubleSquareBracketAttributes; } + /// Return true if the next token should be treated as a [[]] attribute, + /// or as a keyword that behaves like one. The former is only true if + /// [[]] attributes are enabled, whereas the latter is true whenever + /// such a keyword appears. The arguments are as for + /// isCXX11AttributeSpecifier. + bool isAllowedCXX11AttributeSpecifier(bool Disambiguate = false, + bool OuterMightBeMessageSend = false) { + return (Tok.isRegularKeywordAttribute() || + (standardAttributesAllowed() && + isCXX11AttributeSpecifier(Disambiguate, OuterMightBeMessageSend))); + } + // Check for the start of an attribute-specifier-seq in a context where an // attribute is not allowed. bool CheckProhibitedCXX11Attribute() { @@ -2703,11 +2715,13 @@ class Parser : public CodeCompletionHandler { bool DiagnoseProhibitedCXX11Attribute(); void CheckMisplacedCXX11Attribute(ParsedAttributes &Attrs, SourceLocation CorrectLocation) { - if (!standardAttributesAllowed()) - return; - if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) && - Tok.isNot(tok::kw_alignas)) - return; + if (!Tok.isRegularKeywordAttribute()) { + if (!standardAttributesAllowed()) + return; + if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) && + Tok.isNot(tok::kw_alignas)) + return; + } DiagnoseMisplacedCXX11Attribute(Attrs, CorrectLocation); } void DiagnoseMisplacedCXX11Attribute(ParsedAttributes &Attrs, @@ -2721,7 +2735,7 @@ class Parser : public CodeCompletionHandler { SourceLocation FixItLoc = SourceLocation()) { if (Attrs.Range.isInvalid()) return; - DiagnoseProhibitedAttributes(Attrs.Range, FixItLoc); + DiagnoseProhibitedAttributes(Attrs, FixItLoc); Attrs.clear(); } @@ -2729,10 +2743,10 @@ class Parser : public CodeCompletionHandler { SourceLocation FixItLoc = SourceLocation()) { if (Attrs.Range.isInvalid()) return; - DiagnoseProhibitedAttributes(Attrs.Range, FixItLoc); + DiagnoseProhibitedAttributes(Attrs, FixItLoc); Attrs.clearListOnly(); } - void DiagnoseProhibitedAttributes(const SourceRange &Range, + void DiagnoseProhibitedAttributes(const ParsedAttributesView &Attrs, SourceLocation FixItLoc); // Forbid C++11 and C2x attributes that appear on certain syntactic locations @@ -2741,7 +2755,8 @@ class Parser : public CodeCompletionHandler { // For the most cases we don't want to warn on unknown type attributes, but // left them to later diagnoses. However, for a few cases like module // declarations and module import declarations, we should do it. - void ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID, + void ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned AttrDiagID, + unsigned KeywordDiagId, bool DiagnoseEmptyAttrs = false, bool WarnOnUnknownAttrs = false); @@ -2795,7 +2810,7 @@ class Parser : public CodeCompletionHandler { bool MaybeParseAttributes(unsigned WhichAttrKinds, ParsedAttributes &Attrs, LateParsedAttrList *LateAttrs = nullptr) { if (Tok.isOneOf(tok::kw___attribute, tok::kw___declspec) || - (standardAttributesAllowed() && isCXX11AttributeSpecifier())) { + isAllowedCXX11AttributeSpecifier()) { ParseAttributes(WhichAttrKinds, Attrs, LateAttrs); return true; } @@ -2847,7 +2862,7 @@ class Parser : public CodeCompletionHandler { } } void MaybeParseCXX11Attributes(Declarator &D) { - if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) { + if (isAllowedCXX11AttributeSpecifier()) { ParsedAttributes Attrs(AttrFactory); ParseCXX11Attributes(Attrs); D.takeAttributes(Attrs); @@ -2856,8 +2871,7 @@ class Parser : public CodeCompletionHandler { bool MaybeParseCXX11Attributes(ParsedAttributes &Attrs, bool OuterMightBeMessageSend = false) { - if (standardAttributesAllowed() && - isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) { + if (isAllowedCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) { ParseCXX11Attributes(Attrs); return true; } diff --git a/clang/include/clang/Sema/DeclSpec.h b/clang/include/clang/Sema/DeclSpec.h index b0bf87dc18d790..c63378c732908d 100644 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1972,9 +1972,10 @@ class Declarator { InventedTemplateParameterList(nullptr) { assert(llvm::all_of(DeclarationAttrs, [](const ParsedAttr &AL) { - return AL.isStandardAttributeSyntax(); + return (AL.isStandardAttributeSyntax() || + AL.isRegularKeywordAttribute()); }) && - "DeclarationAttrs may only contain [[]] attributes"); + "DeclarationAttrs may only contain [[]] and keyword attributes"); } ~Declarator() { @@ -2619,14 +2620,6 @@ class Declarator { return false; } - /// Return a source range list of C++11 attributes associated - /// with the declarator. - void getCXX11AttributeRanges(SmallVectorImpl &Ranges) { - for (const ParsedAttr &AL : Attrs) - if (AL.isCXX11Attribute()) - Ranges.push_back(AL.getRange()); - } - void setAsmLabel(Expr *E) { AsmLabel = E; } Expr *getAsmLabel() const { return AsmLabel; } diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0e62f0dff980fb..da1d17d14c4c8f 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -1693,30 +1693,43 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() { void Parser::DiagnoseMisplacedCXX11Attribute(ParsedAttributes &Attrs, SourceLocation CorrectLocation) { assert((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) || - Tok.is(tok::kw_alignas)); + Tok.is(tok::kw_alignas) || Tok.isRegularKeywordAttribute()); // Consume the attributes. + auto Keyword = + Tok.isRegularKeywordAttribute() ? Tok.getIdentifierInfo() : nullptr; SourceLocation Loc = Tok.getLocation(); ParseCXX11Attributes(Attrs); CharSourceRange AttrRange(SourceRange(Loc, Attrs.Range.getEnd()), true); // FIXME: use err_attributes_misplaced - Diag(Loc, diag::err_attributes_not_allowed) - << FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange) - << FixItHint::CreateRemoval(AttrRange); + (Keyword ? Diag(Loc, diag::err_keyword_not_allowed) << Keyword + : Diag(Loc, diag::err_attributes_not_allowed)) + << FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange) + << FixItHint::CreateRemoval(AttrRange); } void Parser::DiagnoseProhibitedAttributes( - const SourceRange &Range, const SourceLocation CorrectLocation) { + const ParsedAttributesView &Attrs, const SourceLocation CorrectLocation) { + auto *FirstAttr = Attrs.empty() ? nullptr : &Attrs.front(); if (CorrectLocation.isValid()) { - CharSourceRange AttrRange(Range, true); - Diag(CorrectLocation, diag::err_attributes_misplaced) + CharSourceRange AttrRange(Attrs.Range, true); + (FirstAttr && FirstAttr->isRegularKeywordAttribute() + ? Diag(CorrectLocation, diag::err_keyword_misplaced) << FirstAttr + : Diag(CorrectLocation, diag::err_attributes_misplaced)) << FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange) << FixItHint::CreateRemoval(AttrRange); - } else - Diag(Range.getBegin(), diag::err_attributes_not_allowed) << Range; + } else { + const SourceRange &Range = Attrs.Range; + (FirstAttr && FirstAttr->isRegularKeywordAttribute() + ? Diag(Range.getBegin(), diag::err_keyword_not_allowed) << FirstAttr + : Diag(Range.getBegin(), diag::err_attributes_not_allowed)) + << Range; + } } -void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID, +void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, + unsigned AttrDiagID, + unsigned KeywordDiagID, bool DiagnoseEmptyAttrs, bool WarnOnUnknownAttrs) { @@ -1736,13 +1749,18 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID, // The attribute range starts with [[, but is empty. So this must // be [[]], which we are supposed to diagnose because // DiagnoseEmptyAttrs is true. - Diag(Attrs.Range.getBegin(), DiagID) << Attrs.Range; + Diag(Attrs.Range.getBegin(), AttrDiagID) << Attrs.Range; return; } } } for (const ParsedAttr &AL : Attrs) { + if (AL.isRegularKeywordAttribute()) { + Diag(AL.getLoc(), KeywordDiagID) << AL; + AL.setInvalid(); + continue; + } if (!AL.isCXX11Attribute() && !AL.isC2xAttribute()) continue; if (AL.getKind() == ParsedAttr::UnknownAttribute) { @@ -1750,7 +1768,7 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID, Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL << AL.getRange(); } else { - Diag(AL.getLoc(), DiagID) << AL; + Diag(AL.getLoc(), AttrDiagID) << AL; AL.setInvalid(); } } @@ -1758,8 +1776,10 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID, void Parser::DiagnoseCXX11AttributeExtension(ParsedAttributes &Attrs) { for (const ParsedAttr &PA : Attrs) { - if (PA.isCXX11Attribute() || PA.isC2xAttribute()) - Diag(PA.getLoc(), diag::ext_cxx11_attr_placement) << PA << PA.getRange(); + if (PA.isCXX11Attribute() || PA.isC2xAttribute() || + PA.isRegularKeywordAttribute()) + Diag(PA.getLoc(), diag::ext_cxx11_attr_placement) + << PA << PA.isRegularKeywordAttribute() << PA.getRange(); } } @@ -1991,11 +2011,11 @@ bool Parser::MightBeDeclarator(DeclaratorContext Context) { return getLangOpts().CPlusPlus11 && isCXX11VirtSpecifier(NextToken()); default: - return false; + return Tok.isRegularKeywordAttribute(); } default: - return false; + return Tok.isRegularKeywordAttribute(); } } @@ -3298,13 +3318,17 @@ void Parser::ParseDeclarationSpecifiers( switch (Tok.getKind()) { default: + if (Tok.isRegularKeywordAttribute()) + goto Attribute; + DoneWithDeclSpec: if (!AttrsLastTime) ProhibitAttributes(attrs); else { // Reject C++11 / C2x attributes that aren't type attributes. for (const ParsedAttr &PA : attrs) { - if (!PA.isCXX11Attribute() && !PA.isC2xAttribute()) + if (!PA.isCXX11Attribute() && !PA.isC2xAttribute() && + !PA.isRegularKeywordAttribute()) continue; if (PA.getKind() == ParsedAttr::UnknownAttribute) // We will warn about the unknown attribute elsewhere (in @@ -3323,7 +3347,8 @@ void Parser::ParseDeclarationSpecifiers( if (PA.isTypeAttr() && PA.getKind() != ParsedAttr::AT_LifetimeBound && PA.getKind() != ParsedAttr::AT_AnyX86NoCfCheck) continue; - Diag(PA.getLoc(), diag::err_attribute_not_type_attr) << PA; + Diag(PA.getLoc(), diag::err_attribute_not_type_attr) + << PA << PA.isRegularKeywordAttribute(); PA.setInvalid(); } @@ -3337,9 +3362,10 @@ void Parser::ParseDeclarationSpecifiers( case tok::l_square: case tok::kw_alignas: - if (!standardAttributesAllowed() || !isCXX11AttributeSpecifier()) + if (!isAllowedCXX11AttributeSpecifier()) goto DoneWithDeclSpec; + Attribute: ProhibitAttributes(attrs); // FIXME: It would be good to recover by accepting the attributes, // but attempting to do that now would cause serious @@ -5015,6 +5041,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS, if (IsElaboratedTypeSpecifier && !getLangOpts().MicrosoftExt && !getLangOpts().ObjC) { ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + diag::err_keyword_not_allowed, /*DiagnoseEmptyAttrs=*/true); if (BaseType.isUsable()) Diag(BaseRange.getBegin(), diag::ext_enum_base_in_type_specifier) @@ -5160,7 +5187,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) { // If attributes exist after the enumerator, parse them. ParsedAttributes attrs(AttrFactory); MaybeParseGNUAttributes(attrs); - if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) { + if (isAllowedCXX11AttributeSpecifier()) { if (getLangOpts().CPlusPlus) Diag(Tok.getLocation(), getLangOpts().CPlusPlus17 ? diag::warn_cxx14_compat_ns_enum_attribute @@ -5885,8 +5912,8 @@ void Parser::ParseTypeQualifierListOpt( DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed, bool IdentifierRequired, std::optional> CodeCompletionHandler) { - if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) && - isCXX11AttributeSpecifier()) { + if ((AttrReqs & AR_CXX11AttributesParsed) && + isAllowedCXX11AttributeSpecifier()) { ParsedAttributes Attrs(AttrFactory); ParseCXX11Attributes(Attrs); DS.takeAttributesFrom(Attrs); @@ -6660,6 +6687,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) { PrototypeScope.Exit(); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); + } else if (Tok.isRegularKeywordAttribute()) { + // For consistency with attribute parsing. + Diag(Tok, diag::err_keyword_not_allowed) << Tok.getIdentifierInfo(); + ConsumeToken(); } else if (Tok.is(tok::kw_requires) && D.hasGroupingParens()) { // This declarator is declaring a function, but the requires clause is // in the wrong place: @@ -7064,7 +7095,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D, TrailingReturnTypeLoc = Range.getBegin(); EndLoc = Range.getEnd(); } - } else if (standardAttributesAllowed()) { + } else { MaybeParseCXX11Attributes(FnAttrs); } } diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp index 717c0145208921..32c928e5031b2f 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -635,6 +635,7 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context, Tok.is(tok::identifier) && (NextToken().is(tok::semi) || NextToken().is(tok::comma) || NextToken().is(tok::ellipsis) || NextToken().is(tok::l_square) || + NextToken().isRegularKeywordAttribute() || NextToken().is(tok::kw___attribute)) && D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() && !D.SS.getScopeRep()->getAsNamespace() && @@ -767,11 +768,15 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration( // If we had any misplaced attributes from earlier, this is where they // should have been written. if (MisplacedAttrs.Range.isValid()) { - Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed) + auto *FirstAttr = + MisplacedAttrs.empty() ? nullptr : &MisplacedAttrs.front(); + auto &Range = MisplacedAttrs.Range; + (FirstAttr && FirstAttr->isRegularKeywordAttribute() + ? Diag(Range.getBegin(), diag::err_keyword_not_allowed) << FirstAttr + : Diag(Range.getBegin(), diag::err_attributes_not_allowed)) << FixItHint::CreateInsertionFromRange( - Tok.getLocation(), - CharSourceRange::getTokenRange(MisplacedAttrs.Range)) - << FixItHint::CreateRemoval(MisplacedAttrs.Range); + Tok.getLocation(), CharSourceRange::getTokenRange(Range)) + << FixItHint::CreateRemoval(Range); Attrs.takeAllFrom(MisplacedAttrs); } @@ -1384,6 +1389,8 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) { // This switch enumerates the valid "follow" set for type-specifiers. switch (Tok.getKind()) { default: + if (Tok.isRegularKeywordAttribute()) + return true; break; case tok::semi: // struct foo {...} ; case tok::star: // struct foo {...} * P; @@ -1841,6 +1848,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } else if (isClassCompatibleKeyword() && (NextToken().is(tok::l_square) || NextToken().is(tok::kw_alignas) || + NextToken().isRegularKeywordAttribute() || isCXX11VirtSpecifier(NextToken()) != VirtSpecifiers::VS_None)) { // We can't tell if this is a definition or reference // until we skipped the 'final' and C++11 attribute specifiers. @@ -1862,6 +1870,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, ConsumeParen(); if (!SkipUntil(tok::r_paren, StopAtSemi)) break; + } else if (Tok.isRegularKeywordAttribute()) { + ConsumeToken(); } else { break; } @@ -1898,7 +1908,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, // them to the right place. SourceRange AttrRange = Attributes.Range; if (AttrRange.isValid()) { - Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed) + auto *FirstAttr = Attributes.empty() ? nullptr : &Attributes.front(); + auto Loc = AttrRange.getBegin(); + (FirstAttr && FirstAttr->isRegularKeywordAttribute() + ? Diag(Loc, diag::err_keyword_not_allowed) << FirstAttr + : Diag(Loc, diag::err_attributes_not_allowed)) << AttrRange << FixItHint::CreateInsertionFromRange( AttrFixitLoc, CharSourceRange(AttrRange, true)) @@ -1946,6 +1960,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, TUK == Sema::TUK_Declaration) { // This is an explicit instantiation of a class template. ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + diag::err_keyword_not_allowed, /*DiagnoseEmptyAttrs=*/true); TagOrTempResult = Actions.ActOnExplicitInstantiation( @@ -1962,6 +1977,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, (TUK == Sema::TUK_Friend && TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) { ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + diag::err_keyword_not_allowed, /*DiagnoseEmptyAttrs=*/true); TypeResult = Actions.ActOnTagTemplateIdType( TUK, TagType, StartLoc, SS, TemplateId->TemplateKWLoc, @@ -2031,6 +2047,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } else if (TUK == Sema::TUK_Friend && TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) { ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + diag::err_keyword_not_allowed, /*DiagnoseEmptyAttrs=*/true); TagOrTempResult = Actions.ActOnTemplatedFriendTag( @@ -2041,6 +2058,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind, } else { if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition) ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed, + diag::err_keyword_not_allowed, /* DiagnoseEmptyAttrs=*/true); if (TUK == Sema::TUK_Definition && @@ -3017,12 +3035,14 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS, // // Diagnose attributes that appear in a friend member function declarator: // friend int foo [[]] (); - SmallVector Ranges; - DeclaratorInfo.getCXX11AttributeRanges(Ranges); - for (SmallVectorImpl::iterator I = Ranges.begin(), - E = Ranges.end(); - I != E; ++I) - Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I; + for (const ParsedAttr &AL : DeclaratorInfo.getAttributes()) + if (AL.isCXX11Attribute() || AL.isRegularKeywordAttribute()) { + auto Loc = AL.getRange().getBegin(); + (AL.isRegularKeywordAttribute() + ? Diag(Loc, diag::err_keyword_not_allowed) << AL + : Diag(Loc, diag::err_attributes_not_allowed)) + << AL.getRange(); + } ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, TemplateParams); @@ -4470,6 +4490,14 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, return; } + if (Tok.isRegularKeywordAttribute()) { + SourceLocation Loc = Tok.getLocation(); + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + Attrs.addNew(AttrName, Loc, nullptr, Loc, nullptr, 0, Tok.getKind()); + ConsumeToken(); + return; + } + assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) && "Not a double square bracket attribute list"); @@ -4589,26 +4617,30 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs, /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier void Parser::ParseCXX11Attributes(ParsedAttributes &Attrs) { - assert(standardAttributesAllowed()); + assert(standardAttributesAllowed() || Tok.isRegularKeywordAttribute()); SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc = StartLoc; do { ParseCXX11AttributeSpecifier(Attrs, &EndLoc); - } while (isCXX11AttributeSpecifier()); + } while (isAllowedCXX11AttributeSpecifier()); Attrs.Range = SourceRange(StartLoc, EndLoc); } void Parser::DiagnoseAndSkipCXX11Attributes() { + auto Keyword = + Tok.isRegularKeywordAttribute() ? Tok.getIdentifierInfo() : nullptr; // Start and end location of an attribute or an attribute list. SourceLocation StartLoc = Tok.getLocation(); SourceLocation EndLoc = SkipCXX11Attributes(); if (EndLoc.isValid()) { SourceRange Range(StartLoc, EndLoc); - Diag(StartLoc, diag::err_attributes_not_allowed) << Range; + (Keyword ? Diag(StartLoc, diag::err_keyword_not_allowed) << Keyword + : Diag(StartLoc, diag::err_attributes_not_allowed)) + << Range; } } @@ -4624,6 +4656,9 @@ SourceLocation Parser::SkipCXX11Attributes() { T.consumeOpen(); T.skipToEnd(); EndLoc = T.getCloseLocation(); + } else if (Tok.isRegularKeywordAttribute()) { + EndLoc = Tok.getLocation(); + ConsumeToken(); } else { assert(Tok.is(tok::kw_alignas) && "not an attribute specifier"); ConsumeToken(); diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index 123cf432b0969d..037dc923c47eb0 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1364,7 +1364,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( if (isCXX11AttributeSpecifier()) { Diag(Tok, getLangOpts().CPlusPlus23 ? diag::warn_cxx20_compat_decl_attrs_on_lambda - : diag::ext_decl_attrs_on_lambda); + : diag::ext_decl_attrs_on_lambda) + << Tok.getIdentifierInfo() << Tok.isRegularKeywordAttribute(); MaybeParseCXX11Attributes(D); } @@ -1499,6 +1500,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer( tok::kw___private, tok::kw___global, tok::kw___local, tok::kw___constant, tok::kw___generic, tok::kw_groupshared, tok::kw_requires, tok::kw_noexcept) || + Tok.isRegularKeywordAttribute() || (Tok.is(tok::l_square) && NextToken().is(tok::l_square)); if (HasSpecifiers && !HasParentheses && !getLangOpts().CPlusPlus23) { diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp index 8c3da9a7438e8b..79707bc297f432 100644 --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -1819,7 +1819,8 @@ void Parser::HandlePragmaAttribute() { ConsumeToken(); }; - if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) { + if ((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) || + Tok.isRegularKeywordAttribute()) { // Parse the CXX11 style attribute. ParseCXX11AttributeSpecifier(Attrs); } else if (Tok.is(tok::kw___attribute)) { diff --git a/clang/lib/Parse/ParseStmt.cpp b/clang/lib/Parse/ParseStmt.cpp index bde9df0877382c..aea810e8cf45c8 100644 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -335,7 +335,12 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes( case tok::kw_asm: { for (const ParsedAttr &AL : CXX11Attrs) - Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL; + // Could be relaxed if asm-related regular keyword attributes are + // added later. + (AL.isRegularKeywordAttribute() + ? Diag(AL.getRange().getBegin(), diag::err_keyword_not_allowed) + : Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored)) + << AL; // Prevent these from being interpreted as statement attributes later on. CXX11Attrs.clear(); ProhibitAttributes(GNUAttrs); diff --git a/clang/lib/Parse/ParseTentative.cpp b/clang/lib/Parse/ParseTentative.cpp index ef1f3ca548f6a1..e36ce8aa2bfe41 100644 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -723,6 +723,9 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, if (Tok.is(tok::kw_alignas)) return CAK_AttributeSpecifier; + if (Tok.isRegularKeywordAttribute()) + return CAK_AttributeSpecifier; + if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) return CAK_NotAttributeSpecifier; @@ -862,7 +865,8 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate, bool Parser::TrySkipAttributes() { while (Tok.isOneOf(tok::l_square, tok::kw___attribute, tok::kw___declspec, - tok::kw_alignas)) { + tok::kw_alignas) || + Tok.isRegularKeywordAttribute()) { if (Tok.is(tok::l_square)) { ConsumeBracket(); if (Tok.isNot(tok::l_square)) @@ -873,6 +877,8 @@ bool Parser::TrySkipAttributes() { // Note that explicitly checking for `[[` and `]]` allows to fail as // expected in the case of the Objective-C message send syntax. ConsumeBracket(); + } else if (Tok.isRegularKeywordAttribute()) { + ConsumeToken(); } else { ConsumeToken(); if (Tok.isNot(tok::l_paren)) diff --git a/clang/lib/Parse/Parser.cpp b/clang/lib/Parse/Parser.cpp index 6e44d5f4892be1..b1ccbeb99e5895 100644 --- a/clang/lib/Parse/Parser.cpp +++ b/clang/lib/Parse/Parser.cpp @@ -2461,6 +2461,7 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) { ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr, + diag::err_keyword_not_module_attr, /*DiagnoseEmptyAttrs=*/false, /*WarnOnUnknownAttrs=*/true); @@ -2530,6 +2531,7 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc, MaybeParseCXX11Attributes(Attrs); // We don't support any module import attributes yet. ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr, + diag::err_keyword_not_import_attr, /*DiagnoseEmptyAttrs=*/false, /*WarnOnUnknownAttrs=*/true); diff --git a/clang/lib/Sema/ParsedAttr.cpp b/clang/lib/Sema/ParsedAttr.cpp index 2af688fb58c8a0..d7acb589172b5c 100644 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -203,6 +203,11 @@ bool ParsedAttr::isSupportedByPragmaAttribute() const { } bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const { + if (isRegularKeywordAttribute()) + // The appurtenance rules are applied strictly for all regular keyword + // atributes. + return false; + assert(isStandardAttributeSyntax()); // We have historically allowed some type attributes with standard attribute diff --git a/clang/lib/Sema/Sema.cpp b/clang/lib/Sema/Sema.cpp index 7cc0d472fca02a..b0a8aeddf6034d 100644 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1184,7 +1184,7 @@ void Sema::ActOnEndOfTranslationUnit() { !(isa(PrevDecl) || isa(PrevDecl))) for (const auto &WI : WeakIDs.second) Diag(WI.getLocation(), diag::warn_attribute_wrong_decl_type) - << "'weak'" << ExpectedVariableOrFunction; + << "'weak'" << /*isRegularKeyword=*/0 << ExpectedVariableOrFunction; else for (const auto &WI : WeakIDs.second) Diag(WI.getLocation(), diag::warn_weak_identifier_undeclared) diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index aac57196012aa0..d7c595b4201f10 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5315,10 +5315,14 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS, TypeSpecType == DeclSpec::TST_union || TypeSpecType == DeclSpec::TST_enum) { for (const ParsedAttr &AL : DS.getAttributes()) - Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) + Diag(AL.getLoc(), AL.isRegularKeywordAttribute() + ? diag::err_declspec_keyword_has_no_effect + : diag::warn_declspec_attribute_ignored) << AL << GetDiagnosticTypeSpecifierID(DS); for (const ParsedAttr &AL : DeclAttrs) - Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) + Diag(AL.getLoc(), AL.isRegularKeywordAttribute() + ? diag::err_declspec_keyword_has_no_effect + : diag::warn_declspec_attribute_ignored) << AL << GetDiagnosticTypeSpecifierID(DS); } } diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index f46915a6d6429c..1e48d078a61bb9 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -273,7 +273,9 @@ static bool checkPositiveIntArgument(Sema &S, const AttrInfo &AI, const Expr *Ex template static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { if (const auto *A = D->getAttr()) { - S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << A; + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) + << AL << A + << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute()); S.Diag(A->getLocation(), diag::note_conflicting_attribute); return true; } @@ -283,8 +285,9 @@ static bool checkAttrMutualExclusion(Sema &S, Decl *D, const ParsedAttr &AL) { template static bool checkAttrMutualExclusion(Sema &S, Decl *D, const Attr &AL) { if (const auto *A = D->getAttr()) { - S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) << &AL - << A; + S.Diag(AL.getLocation(), diag::err_attributes_are_not_compatible) + << &AL << A + << (AL.isRegularKeywordAttribute() || A->isRegularKeywordAttribute()); S.Diag(A->getLocation(), diag::note_conflicting_attribute); return true; } @@ -1878,8 +1881,11 @@ static void handleOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Cannot have two ownership attributes of different kinds for the same // index. if (I->getOwnKind() != K && llvm::is_contained(I->args(), Idx)) { - S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) << AL << I; - return; + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) + << AL << I + << (AL.isRegularKeywordAttribute() || + I->isRegularKeywordAttribute()); + return; } else if (K == OwnershipAttr::Returns && I->getOwnKind() == OwnershipAttr::Returns) { // A returns attribute conflicts with any other returns attribute using @@ -2164,7 +2170,7 @@ static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // nonstatic) when in Microsoft compatibility mode. if (S.getLangOpts().MSVCCompat && isa(D)) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type_str) - << AL << "non-member functions"; + << AL << AL.isRegularKeywordAttribute() << "non-member functions"; return; } } @@ -2177,7 +2183,8 @@ static void handleNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &Attrs) { if (!isa(D)) { S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attrs << ExpectedFunctionOrMethod; + << Attrs << Attrs.isRegularKeywordAttribute() + << ExpectedFunctionOrMethod; return; } @@ -2218,7 +2225,9 @@ bool Sema::CheckAttrNoArgs(const ParsedAttr &Attrs) { bool Sema::CheckAttrTarget(const ParsedAttr &AL) { // Check whether the attribute is valid on the current target. if (!AL.existsInTarget(Context.getTargetInfo())) { - Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) + Diag(AL.getLoc(), AL.isRegularKeywordAttribute() + ? diag::err_keyword_not_supported_on_target + : diag::warn_unknown_attribute_ignored) << AL << AL.getRange(); AL.setInvalid(); return true; @@ -2238,7 +2247,8 @@ static void handleAnalyzerNoReturnAttr(Sema &S, Decl *D, const ParsedAttr &AL) { S.Diag(AL.getLoc(), AL.isStandardAttributeSyntax() ? diag::err_attribute_wrong_decl_type : diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionMethodOrBlock; + << AL << AL.isRegularKeywordAttribute() + << ExpectedFunctionMethodOrBlock; return; } } @@ -2888,12 +2898,10 @@ static void handleVisibilityAttr(Sema &S, Decl *D, const ParsedAttr &AL, } // 'type_visibility' can only go on a type or namespace. - if (isTypeVisibility && - !(isa(D) || - isa(D) || - isa(D))) { + if (isTypeVisibility && !(isa(D) || isa(D) || + isa(D))) { S.Diag(AL.getRange().getBegin(), diag::err_attribute_wrong_decl_type) - << AL << ExpectedTypeOrNamespace; + << AL << AL.isRegularKeywordAttribute() << ExpectedTypeOrNamespace; return; } @@ -3112,12 +3120,14 @@ static void handleSentinelAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } } else { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionMethodOrBlock; + << AL << AL.isRegularKeywordAttribute() + << ExpectedFunctionMethodOrBlock; return; } } else { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionMethodOrBlock; + << AL << AL.isRegularKeywordAttribute() + << ExpectedFunctionMethodOrBlock; return; } D->addAttr(::new (S.Context) SentinelAttr(S.Context, AL, sentinel, nullPos)); @@ -3142,7 +3152,8 @@ static void handleWarnUnusedResult(Sema &S, Decl *D, const ParsedAttr &AL) { // as a function pointer. if (isa(D)) S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << AL << "functions, classes, or enumerations"; + << AL << AL.isRegularKeywordAttribute() + << "functions, classes, or enumerations"; // If this is spelled as the standard C++17 attribute, but not in C++17, // warn about using it as an extension. If there are attribute arguments, @@ -3188,7 +3199,7 @@ static void handleWeakImportAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // Nothing to warn about here. } else S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedVariableOrFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedVariableOrFunction; return; } @@ -3884,7 +3895,9 @@ ErrorAttr *Sema::mergeErrorAttr(Decl *D, const AttributeCommonInfo &CI, (EA->isWarning() && NewAttr == "warning"); if (!Match) { Diag(EA->getLocation(), diag::err_attributes_are_not_compatible) - << CI << EA; + << CI << EA + << (CI.isRegularKeywordAttribute() || + EA->isRegularKeywordAttribute()); Diag(CI.getLoc(), diag::note_conflicting_attribute); return nullptr; } @@ -4201,8 +4214,8 @@ static void handleTransparentUnionAttr(Sema &S, Decl *D, const ParsedAttr &AL) { RD = dyn_cast(D); if (!RD || !RD->isUnion()) { - S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) << AL - << ExpectedUnion; + S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedUnion; return; } @@ -4413,7 +4426,7 @@ static bool validateAlignasAppliedType(Sema &S, Decl *D, DiagKind = 4; } else if (!isa(D)) { return S.Diag(AttrLoc, diag::err_attribute_wrong_decl_type) - << &Attr + << &Attr << Attr.isRegularKeywordAttribute() << (Attr.isC11() ? ExpectedVariableOrField : ExpectedVariableFieldOrTag); } @@ -4888,8 +4901,9 @@ InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D, // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass - : ExpectedVariableOrFunction); + << AL << AL.isRegularKeywordAttribute() + << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); return nullptr; } // Attribute does not apply to non-static local variables. @@ -4908,8 +4922,9 @@ Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) { // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { Diag(AL.getLocation(), diag::warn_attribute_wrong_decl_type) - << &AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass - : ExpectedVariableOrFunction); + << &AL << AL.isRegularKeywordAttribute() + << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); return nullptr; } // Attribute does not apply to non-static local variables. @@ -4940,7 +4955,9 @@ SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA, if (const auto *PrevSNA = D->getAttr()) { if (PrevSNA->getName() != Name && !PrevSNA->isImplicit()) { Diag(PrevSNA->getLocation(), diag::err_attributes_are_not_compatible) - << PrevSNA << &SNA; + << PrevSNA << &SNA + << (PrevSNA->isRegularKeywordAttribute() || + SNA.isRegularKeywordAttribute()); Diag(SNA.getLoc(), diag::note_conflicting_attribute); } @@ -5105,7 +5122,7 @@ static void handleCallConvAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isa(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionOrMethod; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; return; } @@ -5236,7 +5253,9 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { : nullptr; if (ExistingDerefType != ParmType.getTypePtrOrNull()) { S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) - << AL << OAttr; + << AL << OAttr + << (AL.isRegularKeywordAttribute() || + OAttr->isRegularKeywordAttribute()); S.Diag(OAttr->getLocation(), diag::note_conflicting_attribute); } return; @@ -5253,7 +5272,9 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { : nullptr; if (ExistingDerefType != ParmType.getTypePtrOrNull()) { S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) - << AL << PAttr; + << AL << PAttr + << (AL.isRegularKeywordAttribute() || + PAttr->isRegularKeywordAttribute()); S.Diag(PAttr->getLocation(), diag::note_conflicting_attribute); } return; @@ -5488,7 +5509,9 @@ void Sema::AddParameterABIAttr(Decl *D, const AttributeCommonInfo &CI, if (auto existingAttr = D->getAttr()) { if (existingAttr->getABI() != abi) { Diag(CI.getLoc(), diag::err_attributes_are_not_compatible) - << getParameterABISpelling(abi) << existingAttr; + << getParameterABISpelling(abi) << existingAttr + << (CI.isRegularKeywordAttribute() || + existingAttr->isRegularKeywordAttribute()); Diag(existingAttr->getLocation(), diag::note_conflicting_attribute); return; } @@ -5680,7 +5703,7 @@ static void handleTypeTagForDatatypeAttr(Sema &S, Decl *D, if (!isa(D)) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type) - << AL << ExpectedVariable; + << AL << AL.isRegularKeywordAttribute() << ExpectedVariable; return; } @@ -5986,7 +6009,8 @@ static void handleXReturnsXRetainedAttr(Sema &S, Decl *D, break; } S.Diag(D->getBeginLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getRange() << AL << ExpectedDeclKind; + << AL.getRange() << AL << AL.isRegularKeywordAttribute() + << ExpectedDeclKind; return; } @@ -6258,10 +6282,12 @@ static void handleObjCBoxable(Sema &S, Decl *D, const ParsedAttr &AL) { } static void handleObjCOwnershipAttr(Sema &S, Decl *D, const ParsedAttr &AL) { - if (hasDeclarator(D)) return; + if (hasDeclarator(D)) + return; S.Diag(D->getBeginLoc(), diag::err_attribute_wrong_decl_type) - << AL.getRange() << AL << ExpectedVariable; + << AL.getRange() << AL << AL.isRegularKeywordAttribute() + << ExpectedVariable; } static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, @@ -6754,7 +6780,8 @@ bool Sema::DiagnoseSwiftName(Decl *D, StringRef Name, SourceLocation Loc, Params = F->parameters(); if (!F->hasWrittenPrototype()) { - Diag(Loc, diag::warn_attribute_wrong_decl_type) << AL + Diag(Loc, diag::warn_attribute_wrong_decl_type) + << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionWithProtoType; return false; } @@ -6875,7 +6902,7 @@ static void handleSwiftNewType(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isa(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << AL << "typedefs"; + << AL << AL.isRegularKeywordAttribute() << "typedefs"; return; } @@ -7350,7 +7377,7 @@ static void handleMSP430InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { // a function with no parameters and void return type. if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'interrupt'" << ExpectedFunctionOrMethod; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; return; } @@ -7423,7 +7450,7 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'interrupt'" << ExpectedFunctionOrMethod; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunctionOrMethod; return; } @@ -7498,7 +7525,8 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { CXXMethodDecl::isStaticOverloadedOperator( cast(D)->getDeclName().getCXXOverloadedOperator())) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionWithProtoType; + << AL << AL.isRegularKeywordAttribute() + << ExpectedFunctionWithProtoType; return; } // Interrupt handler must have void return type. @@ -7554,7 +7582,7 @@ static void handleAnyX86InterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'interrupt'" << ExpectedFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; } @@ -7567,7 +7595,7 @@ static void handleAVRInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) { static void handleAVRSignalAttr(Sema &S, Decl *D, const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'signal'" << ExpectedFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; } @@ -7620,10 +7648,11 @@ BTFDeclTagAttr *Sema::mergeBTFDeclTagAttr(Decl *D, const BTFDeclTagAttr &AL) { return ::new (Context) BTFDeclTagAttr(Context, AL, AL.getBTFDeclTag()); } -static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, const ParsedAttr &AL) { +static void handleWebAssemblyExportNameAttr(Sema &S, Decl *D, + const ParsedAttr &AL) { if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'export_name'" << ExpectedFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; } @@ -7747,7 +7776,7 @@ static void handleRISCVInterruptAttr(Sema &S, Decl *D, if (D->getFunctionType() == nullptr) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'interrupt'" << ExpectedFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; } @@ -7942,7 +7971,7 @@ static void handleX86ForceAlignArgPointerAttr(Sema &S, Decl *D, // Attribute can only be applied to function types. if (!isa(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; return; } @@ -8221,7 +8250,7 @@ static void handleNoSanitizeSpecificAttr(Sema &S, Decl *D, .Case("no_sanitize_memory", "memory"); if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << AL << ExpectedFunction; + << AL << AL.isRegularKeywordAttribute() << ExpectedFunction; // FIXME: Rather than create a NoSanitizeSpecificAttr, this creates a // NoSanitizeAttr object; but we need to calculate the correct spelling list @@ -8682,7 +8711,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, if (AL.getKind() == ParsedAttr::UnknownAttribute || !AL.existsInTarget(S.Context.getTargetInfo())) { S.Diag(AL.getLoc(), - AL.isDeclspecAttribute() + AL.isRegularKeywordAttribute() + ? (unsigned)diag::err_keyword_not_supported_on_target + : AL.isDeclspecAttribute() ? (unsigned)diag::warn_unhandled_ms_attribute_ignored : (unsigned)diag::warn_unknown_attribute_ignored) << AL << AL.getRange(); @@ -8711,7 +8742,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, if (AL.isTypeAttr()) { if (Options.IgnoreTypeAttributes) break; - if (!AL.isStandardAttributeSyntax()) { + if (!AL.isStandardAttributeSyntax() && !AL.isRegularKeywordAttribute()) { // Non-[[]] type attributes are handled in processTypeAttrs(); silently // move on. break; @@ -8776,7 +8807,7 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL, // 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(); + << AL << AL.isRegularKeywordAttribute() << D->getLocation(); break; case ParsedAttr::AT_Interrupt: handleInterruptAttr(S, D, AL); @@ -9487,19 +9518,19 @@ void Sema::ProcessDeclAttributeList( } else if (!D->hasAttr()) { if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction; D->setInvalidDecl(); } else if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction; D->setInvalidDecl(); } else if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction; D->setInvalidDecl(); } else if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << A->isRegularKeywordAttribute() << ExpectedKernelFunction; D->setInvalidDecl(); } } diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 65122c04c4b35e..3169b381071bb1 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -2710,10 +2710,12 @@ BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange, for (const ParsedAttr &AL : Attributes) { if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute) continue; - Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute - ? (unsigned)diag::warn_unknown_attribute_ignored - : (unsigned)diag::err_base_specifier_attribute) - << AL << AL.getRange(); + if (AL.getKind() == ParsedAttr::UnknownAttribute) + Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) + << AL << AL.getRange(); + else + Diag(AL.getLoc(), diag::err_base_specifier_attribute) + << AL << AL.isRegularKeywordAttribute() << AL.getRange(); } TypeSourceInfo *TInfo = nullptr; diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp index 860a5a8524ec71..ad20bc8871f103 100644 --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -490,7 +490,9 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, !(A.existsInTarget(S.Context.getTargetInfo()) || (S.Context.getLangOpts().SYCLIsDevice && Aux && A.existsInTarget(*Aux)))) { - S.Diag(A.getLoc(), A.isDeclspecAttribute() + S.Diag(A.getLoc(), A.isRegularKeywordAttribute() + ? (unsigned)diag::err_keyword_not_supported_on_target + : A.isDeclspecAttribute() ? (unsigned)diag::warn_unhandled_ms_attribute_ignored : (unsigned)diag::warn_unknown_attribute_ignored) << A << A.getRange(); @@ -526,7 +528,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A, // declaration attribute is not written on a statement, but this code is // needed for attributes in Attr.td that do not list any subjects. S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt) - << A << St->getBeginLoc(); + << A << A.isRegularKeywordAttribute() << St->getBeginLoc(); return nullptr; } } diff --git a/clang/lib/Sema/SemaType.cpp b/clang/lib/Sema/SemaType.cpp index d54ac53dd42310..26ad4f97b0d030 100644 --- a/clang/lib/Sema/SemaType.cpp +++ b/clang/lib/Sema/SemaType.cpp @@ -103,8 +103,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr, } } - S.Diag(loc, diag::warn_type_attribute_wrong_type) << name << WhichType - << type; + S.Diag(loc, attr.isRegularKeywordAttribute() + ? diag::err_type_attribute_wrong_type + : diag::warn_type_attribute_wrong_type) + << name << WhichType << type; } // objc_gc applies to Objective-C pointers or, otherwise, to the @@ -685,7 +687,7 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state, for (ParsedAttr &attr : AttrsCopy) { // Do not distribute [[]] attributes. They have strict rules for what // they appertain to. - if (attr.isStandardAttributeSyntax()) + if (attr.isStandardAttributeSyntax() || attr.isRegularKeywordAttribute()) continue; switch (attr.getKind()) { @@ -7334,12 +7336,12 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State, if (Attrs[attr::Ptr32] && Attrs[attr::Ptr64]) { S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) << "'__ptr32'" - << "'__ptr64'"; + << "'__ptr64'" << /*isRegularKeyword=*/0; return true; } else if (Attrs[attr::SPtr] && Attrs[attr::UPtr]) { S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) << "'__sptr'" - << "'__uptr'"; + << "'__uptr'" << /*isRegularKeyword=*/0; return true; } @@ -7862,8 +7864,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, CallingConv CC = fn->getCallConv(); if (CC == CC_X86FastCall) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) - << FunctionType::getNameForCallConv(CC) - << "regparm"; + << FunctionType::getNameForCallConv(CC) << "regparm" + << attr.isRegularKeywordAttribute(); attr.setInvalid(); return true; } @@ -7942,8 +7944,9 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, // and the CCs don't match. if (S.getCallingConvAttributedType(type)) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) - << FunctionType::getNameForCallConv(CC) - << FunctionType::getNameForCallConv(CCOld); + << FunctionType::getNameForCallConv(CC) + << FunctionType::getNameForCallConv(CCOld) + << attr.isRegularKeywordAttribute(); attr.setInvalid(); return true; } @@ -7975,7 +7978,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr, // Also diagnose fastcall with regparm. if (CC == CC_X86FastCall && fn->getHasRegParm()) { S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible) - << "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall); + << "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall) + << attr.isRegularKeywordAttribute(); attr.setInvalid(); return true; } @@ -8491,12 +8495,13 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, if (attr.isInvalid()) continue; - if (attr.isStandardAttributeSyntax()) { + if (attr.isStandardAttributeSyntax() || attr.isRegularKeywordAttribute()) { // [[gnu::...]] attributes are treated as declaration attributes, so may // not appertain to a DeclaratorChunk. If we handle them as type // attributes, accept them in that position and diagnose the GCC // incompatibility. if (attr.isGNUScope()) { + assert(attr.isStandardAttributeSyntax()); bool IsTypeAttr = attr.isTypeAttr(); if (TAL == TAL_DeclChunk) { state.getSema().Diag(attr.getLoc(), @@ -8524,9 +8529,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, switch (attr.getKind()) { default: // A [[]] attribute on a declarator chunk must appertain to a type. - if (attr.isStandardAttributeSyntax() && TAL == TAL_DeclChunk) { + if ((attr.isStandardAttributeSyntax() || + attr.isRegularKeywordAttribute()) && + TAL == TAL_DeclChunk) { state.getSema().Diag(attr.getLoc(), diag::err_attribute_not_type_attr) - << attr; + << attr << attr.isRegularKeywordAttribute(); attr.setUsedAsTypeAttr(); } break; @@ -8707,7 +8714,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type, // Attributes with standard syntax have strict rules for what they // appertain to and hence should not use the "distribution" logic below. - if (attr.isStandardAttributeSyntax()) { + if (attr.isStandardAttributeSyntax() || + attr.isRegularKeywordAttribute()) { if (!handleFunctionTypeAttr(state, attr, type)) { diagnoseBadTypeAttribute(state.getSema(), attr, type); attr.setInvalid(); diff --git a/clang/test/Parser/c2x-attribute-keywords.c b/clang/test/Parser/c2x-attribute-keywords.c new file mode 100644 index 00000000000000..757dc82860110a --- /dev/null +++ b/clang/test/Parser/c2x-attribute-keywords.c @@ -0,0 +1,119 @@ +// RUN: %clang_cc1 -fsyntax-only -triple aarch64-none-linux-gnu -target-feature +sme -verify=expected,notc2x -Wno-strict-prototypes %s +// RUN: %clang_cc1 -fsyntax-only -triple aarch64-none-linux-gnu -target-feature +sme -verify=expected,c2x %s + +enum __arm_streaming E { // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + One __arm_streaming, // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + Two, + Three __arm_streaming // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +}; + +enum __arm_streaming { Four }; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +__arm_streaming enum E2 { Five }; // expected-error {{misplaced '__arm_streaming'}} + +// FIXME: this diagnostic can be improved. +enum { __arm_streaming Six }; // expected-error {{expected identifier}} + +// FIXME: this diagnostic can be improved. +enum E3 __arm_streaming { Seven }; // expected-error {{expected identifier or '('}} + +struct __arm_streaming S1 { // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + int i __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}} + int __arm_streaming j; // expected-error {{'__arm_streaming' only applies to function types}} + int k[10] __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}} + int l __arm_streaming[10]; // expected-error {{'__arm_streaming' only applies to function types}} + __arm_streaming int m, n; // expected-error {{'__arm_streaming' only applies to function types}} + int o __arm_streaming : 12; // expected-error {{'__arm_streaming' only applies to function types}} + int __arm_streaming : 0; // expected-error {{'__arm_streaming' only applies to function types}} + int p, __arm_streaming : 0; // expected-error {{'__arm_streaming' cannot appear here}} + int q, __arm_streaming r; // expected-error {{'__arm_streaming' cannot appear here}} + __arm_streaming int; // expected-error {{'__arm_streaming' cannot appear here}} \ + // expected-warning {{declaration does not declare anything}} +}; + +__arm_streaming struct S2 { int a; }; // expected-error {{misplaced '__arm_streaming'}} +struct S3 __arm_streaming { int a; }; // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} + +union __arm_streaming U { // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + double d __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types; type here is 'double'}} + __arm_streaming int i; // expected-error {{'__arm_streaming' only applies to function types; type here is 'int'}} +}; + +__arm_streaming union U2 { double d; }; // expected-error {{misplaced '__arm_streaming'}} +union U3 __arm_streaming { double d; }; // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} + +struct __arm_streaming IncompleteStruct; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +union __arm_streaming IncompleteUnion; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +enum __arm_streaming IncompleteEnum; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + +__arm_streaming void f1(void); // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +void __arm_streaming f2(void); // expected-error {{'__arm_streaming' only applies to function types}} +void f3 __arm_streaming (void); // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +void f4(void) __arm_streaming; + +void f5(int i __arm_streaming, __arm_streaming int j, int __arm_streaming k); // expected-error 3 {{'__arm_streaming' only applies to function types}} + +void f6(a, b) __arm_streaming int a; int b; { // expected-error {{'__arm_streaming' cannot appear here}} \ + c2x-warning {{deprecated}} +} + +// FIXME: technically, an attribute list cannot appear here, but we currently +// parse it as part of the return type of the function, which is reasonable +// behavior given that we *don't* want to parse it as part of the K&R parameter +// declarations. It is disallowed to avoid a parsing ambiguity we already +// handle well. +int (*f7(a, b))(int, int) __arm_streaming int a; int b; { // c2x-warning {{deprecated}} + return 0; +} + +__arm_streaming int a, b; // expected-error {{'__arm_streaming' only applies to function types}} +int c __arm_streaming, d __arm_streaming; // expected-error 2 {{'__arm_streaming' only applies to function types}} + +void f8(void) __arm_streaming { + __arm_streaming int i, j; // expected-error {{'__arm_streaming' only applies to function types}} + int k, l __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}} +} + +__arm_streaming void f9(void) { // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + int i[10] __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}} + int (*fp1)(void)__arm_streaming; + int (*fp2 __arm_streaming)(void); // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + + int * __arm_streaming *ipp; // expected-error {{'__arm_streaming' only applies to function types}} +} + +void f10(int j[static 10] __arm_streaming, int k[*] __arm_streaming); // expected-error 2 {{'__arm_streaming' only applies to function types}} + +void f11(void) { + __arm_streaming {} // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming if (1) {} // expected-error {{'__arm_streaming' cannot be applied to a statement}} + + __arm_streaming switch (1) { // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming case 1: __arm_streaming break; // expected-error 2 {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming default: break; // expected-error {{'__arm_streaming' cannot be applied to a statement}} + } + + goto foo; + __arm_streaming foo: (void)1; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + + __arm_streaming for (;;); // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming while (1); // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming do __arm_streaming { } while(1); // expected-error 2 {{'__arm_streaming' cannot be applied to a statement}} + + __arm_streaming (void)1; // expected-error {{'__arm_streaming' cannot be applied to a statement}} + + __arm_streaming; // expected-error {{'__arm_streaming' cannot be applied to a statement}} + + (void)sizeof(int [4]__arm_streaming); // expected-error {{'__arm_streaming' only applies to function types}} + (void)sizeof(struct __arm_streaming S3 { int a __arm_streaming; }); // expected-error {{'__arm_streaming' cannot be applied to a declaration}} \ + // expected-error {{'__arm_streaming' only applies to function types; type here is 'int'}} + + __arm_streaming return; // expected-error {{'__arm_streaming' cannot be applied to a statement}} + + __arm_streaming asm (""); // expected-error {{'__arm_streaming' cannot appear here}} +} + +struct __arm_streaming S4 *s; // expected-error {{'__arm_streaming' cannot appear here}} +struct S5 {}; +int c = sizeof(struct __arm_streaming S5); // expected-error {{'__arm_streaming' cannot appear here}} diff --git a/clang/test/Parser/c2x-attribute-keywords.m b/clang/test/Parser/c2x-attribute-keywords.m new file mode 100644 index 00000000000000..d1c45da34fbc60 --- /dev/null +++ b/clang/test/Parser/c2x-attribute-keywords.m @@ -0,0 +1,19 @@ +// RUN: %clang_cc1 -fsyntax-only -triple aarch64-none-linux-gnu -target-feature +sme -verify %s + +enum __arm_streaming E1 : int; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + +@interface Base +@end + +@interface S : Base +- (void) bar; +@end + +@interface T : Base +- (S *) foo; +@end + + +void f(T *t) { + __arm_streaming[[t foo] bar]; // expected-error {{'__arm_streaming' cannot be applied to a statement}} +} diff --git a/clang/test/Parser/cxx0x-keyword-attributes.cpp b/clang/test/Parser/cxx0x-keyword-attributes.cpp new file mode 100644 index 00000000000000..256a834e9e5460 --- /dev/null +++ b/clang/test/Parser/cxx0x-keyword-attributes.cpp @@ -0,0 +1,345 @@ +// RUN: %clang_cc1 -fcxx-exceptions -fdeclspec -fexceptions -fsyntax-only -verify -std=c++11 -Wc++14-compat -Wc++14-extensions -Wc++17-extensions -triple aarch64-none-linux-gnu %s + +// Need std::initializer_list +namespace std { + typedef decltype(sizeof(int)) size_t; + + // libc++'s implementation + template + class initializer_list + { + const _E* __begin_; + size_t __size_; + + initializer_list(const _E* __b, size_t __s) + : __begin_(__b), + __size_(__s) + {} + + public: + typedef _E value_type; + typedef const _E& reference; + typedef const _E& const_reference; + typedef size_t size_type; + + typedef const _E* iterator; + typedef const _E* const_iterator; + + initializer_list() : __begin_(nullptr), __size_(0) {} + + size_t size() const {return __size_;} + const _E* begin() const {return __begin_;} + const _E* end() const {return __begin_ + __size_;} + }; +} + + +// Declaration syntax checks +__arm_streaming int before_attr; // expected-error {{'__arm_streaming' only applies to function types}} +int __arm_streaming between_attr; // expected-error {{'__arm_streaming' only applies to function types}} +const __arm_streaming int between_attr_2 = 0; // expected-error {{'__arm_streaming' cannot appear here}} +int after_attr __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}} +int * __arm_streaming ptr_attr; // expected-error {{'__arm_streaming' only applies to function types}} +int & __arm_streaming ref_attr = after_attr; // expected-error {{'__arm_streaming' only applies to function types}} +int && __arm_streaming rref_attr = 0; // expected-error {{'__arm_streaming' only applies to function types}} +int array_attr [1] __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}} +void fn_attr () __arm_streaming; +void noexcept_fn_attr () noexcept __arm_streaming; +struct MemberFnOrder { + virtual void f() const volatile && noexcept __arm_streaming final = 0; +}; +struct __arm_streaming struct_attr; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +class __arm_streaming class_attr {}; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +union __arm_streaming union_attr; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +enum __arm_streaming E { }; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +namespace test_misplacement { +__arm_streaming struct struct_attr2; // expected-error {{misplaced '__arm_streaming'}} +__arm_streaming class class_attr2; // expected-error {{misplaced '__arm_streaming'}} +__arm_streaming union union_attr2; // expected-error {{misplaced '__arm_streaming'}} +__arm_streaming enum E2 { }; // expected-error {{misplaced '__arm_streaming'}} +} + +// Checks attributes placed at wrong syntactic locations of class specifiers. +class __arm_streaming __arm_streaming // expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} + attr_after_class_name_decl __arm_streaming __arm_streaming; // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} + +class __arm_streaming __arm_streaming // expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} + attr_after_class_name_definition __arm_streaming __arm_streaming __arm_streaming{}; // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error 3 {{'__arm_streaming' cannot be applied to a declaration}} + +class __arm_streaming c {}; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +class c __arm_streaming __arm_streaming x; // expected-error 2 {{'__arm_streaming' only applies to function types}} +class c __arm_streaming __arm_streaming y __arm_streaming __arm_streaming; // expected-error 4 {{'__arm_streaming' only applies to function types}} +class c final [(int){0}]; + +class base {}; +class __arm_streaming __arm_streaming final_class // expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} + __arm_streaming alignas(float) final // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} + __arm_streaming alignas(float) __arm_streaming alignas(float): base{}; // expected-error {{'__arm_streaming' cannot appear here}} + +class __arm_streaming __arm_streaming final_class_another // expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} + __arm_streaming __arm_streaming alignas(16) final // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} + __arm_streaming __arm_streaming alignas(16) __arm_streaming{}; // expected-error {{'__arm_streaming' cannot appear here}} + +class after_class_close {} __arm_streaming; // expected-error {{'__arm_streaming' cannot appear here, place it after "class" to apply it to the type declaration}} + +class C {}; + +__arm_streaming struct with_init_declarators {} init_declarator; // expected-error {{'__arm_streaming' only applies to function types}} +__arm_streaming struct no_init_declarators; // expected-error {{misplaced '__arm_streaming'}} +template __arm_streaming struct no_init_declarators_template; // expected-error {{'__arm_streaming' cannot appear here}} +void fn_with_structs() { + __arm_streaming struct with_init_declarators {} init_declarator; // expected-error {{'__arm_streaming' only applies to function types}} + __arm_streaming struct no_init_declarators; // expected-error {{'__arm_streaming' cannot appear here}} +} +__arm_streaming; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +struct ctordtor { + __arm_streaming ctordtor __arm_streaming () __arm_streaming; // expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} + ctordtor (C) __arm_streaming; + __arm_streaming ~ctordtor __arm_streaming () __arm_streaming; // expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} +}; +__arm_streaming ctordtor::ctordtor __arm_streaming () __arm_streaming {} // expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} +__arm_streaming ctordtor::ctordtor (C) __arm_streaming try {} catch (...) {} // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +__arm_streaming ctordtor::~ctordtor __arm_streaming () __arm_streaming {} // expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} +extern "C++" __arm_streaming int extern_attr; // expected-error {{'__arm_streaming' only applies to function types}} +template __arm_streaming void template_attr (); // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +__arm_streaming __arm_streaming int __arm_streaming __arm_streaming multi_attr __arm_streaming __arm_streaming; // expected-error 6 {{'__arm_streaming' only applies to function types}} + +int (paren_attr) __arm_streaming; // expected-error {{'__arm_streaming' cannot appear here}} +unsigned __arm_streaming int attr_in_decl_spec; // expected-error {{'__arm_streaming' cannot appear here}} +unsigned __arm_streaming int __arm_streaming const double_decl_spec = 0; // expected-error 2 {{'__arm_streaming' cannot appear here}} +class foo { + void const_after_attr () __arm_streaming const; // expected-error {{expected ';'}} +}; +extern "C++" __arm_streaming { } // expected-error {{'__arm_streaming' cannot appear here}} +__arm_streaming extern "C++" { } // expected-error {{'__arm_streaming' cannot appear here}} +__arm_streaming template void before_template_attr (); // expected-error {{'__arm_streaming' cannot appear here}} +__arm_streaming namespace ns { int i; } // expected-error {{'__arm_streaming' cannot appear here}} +__arm_streaming static_assert(true, ""); //expected-error {{'__arm_streaming' cannot appear here}} +__arm_streaming asm(""); // expected-error {{'__arm_streaming' cannot appear here}} + +__arm_streaming using ns::i; // expected-warning {{ISO C++}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} +__arm_streaming using namespace ns; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +namespace __arm_streaming ns2 {} // expected-warning {{attributes on a namespace declaration are a C++17 extension}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} + +using __arm_streaming alignas(4)__arm_streaming ns::i; // expected-warning 2 {{ISO C++}} \ + expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error {{'alignas' attribute only applies to variables, data members and tag types}} \ + expected-warning {{ISO C++}} \ + expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} +using __arm_streaming alignas(4) __arm_streaming foobar = int; // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error {{'alignas' attribute only applies to}} \ + expected-error 2 {{'__arm_streaming' only applies to function types}} + +__arm_streaming using T = int; // expected-error {{'__arm_streaming' cannot appear here}} +using T __arm_streaming = int; // expected-error {{'__arm_streaming' only applies to function types}} +template using U __arm_streaming = T; // expected-error {{'__arm_streaming' only applies to function types}} +using ns::i __arm_streaming; // expected-warning {{ISO C++}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} +using ns::i __arm_streaming, ns::i __arm_streaming; // expected-warning 2 {{ISO C++}} \ + expected-warning {{use of multiple declarators in a single using declaration is a C++17 extension}} \ + expected-error 2 {{'__arm_streaming' cannot be applied to a declaration}} +struct using_in_struct_base { + typedef int i, j, k, l; +}; +struct using_in_struct : using_in_struct_base { + __arm_streaming using using_in_struct_base::i; // expected-warning {{ISO C++}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} + using using_in_struct_base::j __arm_streaming; // expected-warning {{ISO C++}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} + __arm_streaming using using_in_struct_base::k __arm_streaming, using_in_struct_base::l __arm_streaming; // expected-warning 3 {{ISO C++}} \ + expected-warning {{use of multiple declarators in a single using declaration is a C++17 extension}} \ + expected-error 4 {{'__arm_streaming' cannot be applied to a declaration}} +}; +using __arm_streaming ns::i; // expected-warning {{ISO C++}} \ + expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} +using T __arm_streaming = int; // expected-error {{'__arm_streaming' only applies to function types}} + +auto trailing() -> __arm_streaming const int; // expected-error {{'__arm_streaming' cannot appear here}} +auto trailing() -> const __arm_streaming int; // expected-error {{'__arm_streaming' cannot appear here}} +auto trailing() -> const int __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}} +auto trailing_2() -> struct struct_attr __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}} + +namespace N { + struct S {}; +}; +template struct Template {}; + +// FIXME: Improve this diagnostic +struct __arm_streaming N::S s; // expected-error {{'__arm_streaming' cannot appear here}} +struct __arm_streaming Template t; // expected-error {{'__arm_streaming' cannot appear here}} +struct __arm_streaming ::template Template u; // expected-error {{'__arm_streaming' cannot appear here}} +template struct __arm_streaming Template; // expected-error {{'__arm_streaming' cannot appear here}} +template struct __attribute__((pure)) Template; // We still allow GNU-style attributes here +template <> struct __arm_streaming Template; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + +enum __arm_streaming E1 {}; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +enum __arm_streaming E2; // expected-error {{forbids forward references}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} +enum __arm_streaming E1; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +enum __arm_streaming E3 : int; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +enum __arm_streaming { // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + k_123 __arm_streaming = 123 // expected-warning {{attributes on an enumerator declaration are a C++17 extension}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} +}; +enum __arm_streaming E1 e; // expected-error {{'__arm_streaming' cannot appear here}} +enum __arm_streaming class E4 { }; // expected-error {{'__arm_streaming' cannot appear here}} +enum struct __arm_streaming E5; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} +enum E6 {} __arm_streaming; // expected-error {{'__arm_streaming' cannot appear here, place it after "enum" to apply it to the type declaration}} + +struct S { + friend int f __arm_streaming (); // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} + friend int f2 __arm_streaming () {} // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + __arm_streaming friend int g(); // expected-error {{'__arm_streaming' cannot appear here}} + __arm_streaming friend int h() { // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + } + __arm_streaming friend int f3(), f4(), f5(); // expected-error {{'__arm_streaming' cannot appear here}} + friend int f6 __arm_streaming (), f7 __arm_streaming (), f8 __arm_streaming (); // expected-error3 {{'__arm_streaming' cannot appear here}} \ + expected-error 3 {{'__arm_streaming' cannot be applied to a declaration}} + friend class __arm_streaming C; // expected-error {{'__arm_streaming' cannot appear here}} + __arm_streaming friend class D; // expected-error {{'__arm_streaming' cannot appear here}} + __arm_streaming friend int; // expected-error {{'__arm_streaming' cannot appear here}} +}; +template void tmpl (T) {} +template __arm_streaming void tmpl(char); // expected-error {{'__arm_streaming' cannot appear here}} +template void __arm_streaming tmpl(short); // expected-error {{'__arm_streaming' only applies to function types}} + +// Statement tests +void foo () { + __arm_streaming ; // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming { } // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming if (0) { } // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming for (;;); // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming do { // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming continue; // expected-error {{'__arm_streaming' cannot be applied to a statement}} + } while (0); + __arm_streaming while (0); // expected-error {{'__arm_streaming' cannot be applied to a statement}} + + __arm_streaming switch (i) { // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming case 0: // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming default: // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming break; // expected-error {{'__arm_streaming' cannot be applied to a statement}} + } + + __arm_streaming goto there; // expected-error {{'__arm_streaming' cannot be applied to a statement}} + __arm_streaming there: // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + + __arm_streaming try { // expected-error {{'__arm_streaming' cannot be applied to a statement}} + } __arm_streaming catch (...) { // expected-error {{'__arm_streaming' cannot appear here}} + } + + void bar __arm_streaming (__arm_streaming int i, __arm_streaming int j); // expected-error 2 {{'__arm_streaming' only applies to function types}} \ + expected-error {{'__arm_streaming' cannot be applied to a declaration}} + using FuncType = void (__arm_streaming int); // expected-error {{'__arm_streaming' only applies to function types}} + void baz(__arm_streaming...); // expected-error {{expected parameter declarator}} + + __arm_streaming return; // expected-error {{'__arm_streaming' cannot be applied to a statement}} +} + +// Expression tests +void bar () { + new int[42]__arm_streaming[5]__arm_streaming{}; // expected-error {{'__arm_streaming' only applies to function types}} +} + +// Condition tests +void baz () { + if (__arm_streaming bool b = true) { // expected-error {{'__arm_streaming' only applies to function types}} + switch (__arm_streaming int n { 42 }) { // expected-error {{'__arm_streaming' only applies to function types}} + default: + for (__arm_streaming int n = 0; __arm_streaming char b = n < 5; ++b) { // expected-error 2 {{'__arm_streaming' only applies to function types}} + } + } + } + int x; + // An attribute can be applied to an expression-statement, such as the first + // statement in a for. But it can't be applied to a condition which is an + // expression. + for (__arm_streaming x = 0; ; ) {} // expected-error {{'__arm_streaming' cannot appear here}} + for (; __arm_streaming x < 5; ) {} // expected-error {{'__arm_streaming' cannot appear here}} + while (__arm_streaming bool k { false }) { // expected-error {{'__arm_streaming' only applies to function types}} + } + while (__arm_streaming true) { // expected-error {{'__arm_streaming' cannot appear here}} + } + do { + } while (__arm_streaming false); // expected-error {{'__arm_streaming' cannot appear here}} + + for (__arm_streaming int n : { 1, 2, 3 }) { // expected-error {{'__arm_streaming' only applies to function types}} + } +} + +enum class __attribute__((visibility("hidden"))) SecretKeepers { + one, /* rest are deprecated */ two, three +}; +enum class __arm_streaming EvenMoreSecrets {}; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + +// Forbid attributes on decl specifiers. +unsigned __arm_streaming static int __arm_streaming v1; // expected-error {{'__arm_streaming' only applies to function types}} \ + expected-error {{'__arm_streaming' cannot appear here}} +typedef __arm_streaming unsigned long __arm_streaming v2; // expected-error {{'__arm_streaming' only applies to function types}} \ + expected-error {{'__arm_streaming' cannot appear here}} +int __arm_streaming foo(int __arm_streaming x); // expected-error 2 {{'__arm_streaming' only applies to function types}} + +__arm_streaming; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} + +class A { + A(__arm_streaming int a); // expected-error {{'__arm_streaming' only applies to function types}} +}; +A::A(__arm_streaming int a) {} // expected-error {{'__arm_streaming' only applies to function types}} + +template struct TemplateStruct {}; +class FriendClassesWithAttributes { + // We allow GNU-style attributes here + template friend class __attribute__((__type_visibility__("default"))) vector; + template friend class __declspec(code_seg("foo,whatever")) vector2; + // But not C++11 ones + template friend class __arm_streaming vector3; // expected-error {{'__arm_streaming' cannot appear here}} + + // Also allowed + friend struct __attribute__((__type_visibility__("default"))) TemplateStruct; + friend struct __declspec(code_seg("foo,whatever")) TemplateStruct; + friend struct __arm_streaming TemplateStruct; // expected-error {{'__arm_streaming' cannot appear here}} +}; + +// Check ordering: C++11 attributes must appear before GNU attributes. +class Ordering { + void f1( + int (__arm_streaming __attribute__(()) int n) // expected-error {{'__arm_streaming' only applies to function types}} + ) { + } + + void f2( + int (*)(__arm_streaming __attribute__(()) int n) // expected-error {{'__arm_streaming' only applies to function types}} + ) { + } + + void f3( + int (__attribute__(()) __arm_streaming int n) // expected-error {{'__arm_streaming' cannot appear here}} + ) { + } + + void f4( + int (*)(__attribute__(()) __arm_streaming int n) // expected-error {{'__arm_streaming' cannot appear here}} + ) { + } +}; + +namespace base_specs { +struct A {}; +struct B : __arm_streaming A {}; // expected-error {{'__arm_streaming' cannot be applied to a base specifier}} +struct C : __arm_streaming virtual A {}; // expected-error {{'__arm_streaming' cannot be applied to a base specifier}} +struct D : __arm_streaming public virtual A {}; // expected-error {{'__arm_streaming' cannot be applied to a base specifier}} +struct E : public __arm_streaming virtual A {}; // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error {{'__arm_streaming' cannot be applied to a base specifier}} +struct F : virtual __arm_streaming public A {}; // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error {{'__arm_streaming' cannot be applied to a base specifier}} +} + +namespace __arm_streaming ns_attr {}; // expected-error {{'__arm_streaming' cannot be applied to a declaration}} \ + expected-warning {{attributes on a namespace declaration are a C++17 extension}} diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index a05c7ab66a7a13..dc3434d61d329f 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -3882,7 +3882,8 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, "; OS << "const Decl *D) const override {\n"; OS << " S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n"; - OS << " << AL << D->getLocation();\n"; + OS << " << AL << AL.isRegularKeywordAttribute() << " + "D->getLocation();\n"; OS << " return false;\n"; OS << "}\n\n"; } @@ -3911,7 +3912,7 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { OS << (Warn ? "warn_attribute_wrong_decl_type_str" : "err_attribute_wrong_decl_type_str"); OS << ")\n"; - OS << " << Attr << "; + OS << " << Attr << Attr.isRegularKeywordAttribute() << "; OS << CalculateDiagnostic(*SubjectObj) << ";\n"; OS << " return false;\n"; OS << " }\n"; @@ -3926,7 +3927,8 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { OS << "bool diagAppertainsToStmt(Sema &S, const ParsedAttr &AL, "; OS << "const Stmt *St) const override {\n"; OS << " S.Diag(AL.getLoc(), diag::err_decl_attribute_invalid_on_stmt)\n"; - OS << " << AL << St->getBeginLoc();\n"; + OS << " << AL << AL.isRegularKeywordAttribute() << " + "St->getBeginLoc();\n"; OS << " return false;\n"; OS << "}\n\n"; } @@ -3945,7 +3947,7 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { OS << (Warn ? "warn_attribute_wrong_decl_type_str" : "err_attribute_wrong_decl_type_str"); OS << ")\n"; - OS << " << Attr << "; + OS << " << Attr << Attr.isRegularKeywordAttribute() << "; OS << CalculateDiagnostic(*SubjectObj) << ";\n"; OS << " return false;\n"; OS << " }\n"; @@ -4016,7 +4018,8 @@ static void GenerateMutualExclusionsChecks(const Record &Attr, for (const std::string &A : DeclAttrs) { OS << " if (const auto *A = D->getAttr<" << A << ">()) {\n"; OS << " S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)" - << " << AL << A;\n"; + << " << AL << A << (AL.isRegularKeywordAttribute() ||" + << " A->isRegularKeywordAttribute());\n"; OS << " S.Diag(A->getLocation(), diag::note_conflicting_attribute);"; OS << " \nreturn false;\n"; OS << " }\n"; @@ -4037,7 +4040,8 @@ static void GenerateMutualExclusionsChecks(const Record &Attr, << ">()) {\n"; MergeDeclOS << " S.Diag(First->getLocation(), " << "diag::err_attributes_are_not_compatible) << First << " - << "Second;\n"; + << "Second << (First->isRegularKeywordAttribute() || " + << "Second->isRegularKeywordAttribute());\n"; MergeDeclOS << " S.Diag(Second->getLocation(), " << "diag::note_conflicting_attribute);\n"; MergeDeclOS << " return false;\n"; @@ -4077,7 +4081,8 @@ static void GenerateMutualExclusionsChecks(const Record &Attr, MergeStmtOS << " if (Iter != C.end()) {\n"; MergeStmtOS << " S.Diag((*Iter)->getLocation(), " << "diag::err_attributes_are_not_compatible) << *Iter << " - << "Second;\n"; + << "Second << ((*Iter)->isRegularKeywordAttribute() || " + << "Second->isRegularKeywordAttribute());\n"; MergeStmtOS << " S.Diag(Second->getLocation(), " << "diag::note_conflicting_attribute);\n"; MergeStmtOS << " return false;\n";