diff --git a/clang/examples/Attribute/Attribute.cpp b/clang/examples/Attribute/Attribute.cpp --- a/clang/examples/Attribute/Attribute.cpp +++ b/clang/examples/Attribute/Attribute.cpp @@ -40,7 +40,7 @@ // This attribute appertains to functions only. if (!isa(D)) { S.Diag(Attr.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << Attr << "functions"; + << Attr << 0 << "functions"; return false; } return true; diff --git a/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp b/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp --- a/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp +++ b/clang/examples/CallSuperAttribute/CallSuperAttrInfo.cpp @@ -169,7 +169,7 @@ 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 << 0 << "virtual functions"; return false; } MarkedMethods.insert(TheMethod); diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -2388,37 +2388,37 @@ } def ArmStreamingCompatible : TypeAttr, TargetSpecificAttr { - let Spellings = [GNU<"arm_streaming_compatible">]; + let Spellings = [Keyword<"__arm_streaming_compatible">]; let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>; let Documentation = [ArmSmeStreamingCompatibleDocs]; } def ArmStreaming : TypeAttr, TargetSpecificAttr { - let Spellings = [GNU<"arm_streaming">]; + let Spellings = [Keyword<"__arm_streaming">]; let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>; let Documentation = [ArmSmeStreamingDocs]; } def ArmLocallyStreaming : InheritableAttr, TargetSpecificAttr { - let Spellings = [GNU<"arm_locally_streaming">]; + let Spellings = [Keyword<"__arm_locally_streaming">]; let Subjects = SubjectList<[Function], ErrorDiag>; let Documentation = [ArmSmeLocallyStreamingDocs]; } def ArmSharedZA : TypeAttr, TargetSpecificAttr { - let Spellings = [GNU<"arm_shared_za">]; + let Spellings = [Keyword<"__arm_shared_za">]; let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>; let Documentation = [ArmSmeSharedZADocs]; } def ArmPreservesZA : TypeAttr, TargetSpecificAttr { - let Spellings = [GNU<"arm_preserves_za">]; + let Spellings = [Keyword<"__arm_preserves_za">]; let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>; let Documentation = [ArmSmePreservesZADocs]; } def ArmNewZA : TypeAttr, TargetSpecificAttr { - let Spellings = [GNU<"arm_new_za">]; + let Spellings = [Keyword<"__arm_new_za">]; let Subjects = SubjectList<[HasFunctionProto], ErrorDiag>; let Documentation = [ArmSmeNewZADocs]; } 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 @@ -51,6 +51,9 @@ /// : AS_HLSLSemantic, + + /// A keyword that can appear wherever a standard attribute can appear. + AS_AttributeLikeKeyword, }; enum Kind { #define PARSED_ATTR(NAME) AT_##NAME, @@ -190,6 +193,10 @@ return SyntaxUsed == AS_ContextSensitiveKeyword; } + bool isAttributeLikeKeyword() const { + return SyntaxUsed == AS_AttributeLikeKeyword; + } + unsigned getAttributeSpellingListIndex() const { assert((isAttributeSpellingListCalculated() || AttrName) && "Spelling cannot be found"); diff --git a/clang/include/clang/Basic/DiagnosticCommonKinds.td b/clang/include/clang/Basic/DiagnosticCommonKinds.td --- a/clang/include/clang/Basic/DiagnosticCommonKinds.td +++ b/clang/include/clang/Basic/DiagnosticCommonKinds.td @@ -117,7 +117,7 @@ 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< @@ -165,6 +165,8 @@ "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 --- a/clang/include/clang/Basic/DiagnosticParseKinds.td +++ b/clang/include/clang/Basic/DiagnosticParseKinds.td @@ -738,10 +738,12 @@ 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|%1}0 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">; @@ -1019,14 +1021,15 @@ 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++2b extension">, - InGroup; + "%select{an attribute specifier sequence|%1}0 in this position " + "is a C++2b extension">, InGroup; def ext_lambda_missing_parens : ExtWarn< "lambda without a parameter clause is a C++2b 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++2b">, InGroup, DefaultIgnore; + "%select{an attribute specifier sequence|%1}0 in this position " + "is incompatible with C++ standards before C++2b">, + InGroup, DefaultIgnore; // C++17 lambda expressions def err_expected_star_this_capture : Error< @@ -1583,8 +1586,12 @@ "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 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -3008,7 +3008,7 @@ 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">; @@ -3405,9 +3405,9 @@ 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; @@ -3513,11 +3513,11 @@ 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" @@ -3530,13 +3530,15 @@ "|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>; @@ -3590,7 +3592,7 @@ 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/Basic/TokenKinds.h b/clang/include/clang/Basic/TokenKinds.h --- a/clang/include/clang/Basic/TokenKinds.h +++ b/clang/include/clang/Basic/TokenKinds.h @@ -99,6 +99,13 @@ /// Return true if this is an annotation token representing a pragma. bool isPragmaAnnotation(TokenKind K); +/// Return true if K is a keyword that is parsed in the same position as +/// a C++11 attribute, but that has semantic meaning and so is not suitable +/// to be a true attribute. +inline bool isAttributeLikeKeyword(TokenKind K) { + return K >= tok::kw___arm_streaming && K <= tok::kw___arm_preserves_za; +} + } // end namespace tok } // end namespace clang diff --git a/clang/include/clang/Basic/TokenKinds.def b/clang/include/clang/Basic/TokenKinds.def --- a/clang/include/clang/Basic/TokenKinds.def +++ b/clang/include/clang/Basic/TokenKinds.def @@ -678,6 +678,17 @@ KEYWORD(_Nullable_result , KEYALL) KEYWORD(_Null_unspecified , KEYALL) +// Keywords that are parsed in the same position as C++11 attributes, +// but that have semantic meaning and so would not make suitable standard +// attributes themselves. This list needs to be kept in sync with +// isAttributeLikeKeyword in TokenKinds.h. +KEYWORD(__arm_streaming , KEYALL) +KEYWORD(__arm_streaming_compatible , KEYALL) +KEYWORD(__arm_locally_streaming , KEYALL) +KEYWORD(__arm_new_za , KEYALL) +KEYWORD(__arm_shared_za , KEYALL) +KEYWORD(__arm_preserves_za , KEYALL) + // Microsoft extensions which should be disabled in strict conformance mode KEYWORD(__ptr64 , KEYMS) KEYWORD(__ptr32 , KEYMS) diff --git a/clang/include/clang/Lex/Token.h b/clang/include/clang/Lex/Token.h --- a/clang/include/clang/Lex/Token.h +++ b/clang/include/clang/Lex/Token.h @@ -117,8 +117,13 @@ } /// Return true if this is any of tok::annot_* kind tokens. - bool isAnnotation() const { - return tok::isAnnotation(getKind()); + bool isAnnotation() const { return tok::isAnnotation(getKind()); } + + /// Return true if K is a keyword that is parsed in the same position as + /// a C++11 attribute, but that has semantic meaning and so is not suitable + /// to be a true attribute. + bool isAttributeLikeKeyword() const { + return tok::isAttributeLikeKeyword(getKind()); } /// Return a source location identifier for the specified 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 @@ -2677,6 +2677,17 @@ return LO.DoubleSquareBracketAttributes; } + /// Should the next token be treated as a [[]] attribute, or 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.isAttributeLikeKeyword() || + (standardAttributesAllowed() && + isCXX11AttributeSpecifier(Disambiguate, OuterMightBeMessageSend))); + } + // Check for the start of an attribute-specifier-seq in a context where an // attribute is not allowed. bool CheckProhibitedCXX11Attribute() { @@ -2689,11 +2700,13 @@ 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.isAttributeLikeKeyword()) { + 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, @@ -2707,7 +2720,7 @@ SourceLocation FixItLoc = SourceLocation()) { if (Attrs.Range.isInvalid()) return; - DiagnoseProhibitedAttributes(Attrs.Range, FixItLoc); + DiagnoseProhibitedAttributes(Attrs, FixItLoc); Attrs.clear(); } @@ -2715,10 +2728,10 @@ 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 @@ -2727,7 +2740,8 @@ // 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); @@ -2781,7 +2795,7 @@ 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; } @@ -2833,7 +2847,7 @@ } } void MaybeParseCXX11Attributes(Declarator &D) { - if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) { + if (isAllowedCXX11AttributeSpecifier()) { ParsedAttributes Attrs(AttrFactory); ParseCXX11Attributes(Attrs); D.takeAttributes(Attrs); @@ -2842,8 +2856,7 @@ 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 --- a/clang/include/clang/Sema/DeclSpec.h +++ b/clang/include/clang/Sema/DeclSpec.h @@ -1956,9 +1956,10 @@ InventedTemplateParameterList(nullptr) { assert(llvm::all_of(DeclarationAttrs, [](const ParsedAttr &AL) { - return AL.isStandardAttributeSyntax(); + return (AL.isStandardAttributeSyntax() || + AL.isAttributeLikeKeyword()); }) && - "DeclarationAttrs may only contain [[]] attributes"); + "DeclarationAttrs may only contain [[]] and keyword attributes"); } ~Declarator() { @@ -2603,14 +2604,6 @@ 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/AST/TypePrinter.cpp b/clang/lib/AST/TypePrinter.cpp --- a/clang/lib/AST/TypePrinter.cpp +++ b/clang/lib/AST/TypePrinter.cpp @@ -912,20 +912,20 @@ if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMCompatibleMask) && !InsideCCAttribute) - OS << " __attribute__((arm_streaming_compatible))"; + OS << " __arm_streaming_compatible"; if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateSMEnabledMask) && !InsideCCAttribute) - OS << " __attribute__((arm_streaming))"; + OS << " __arm_streaming"; if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateZANewMask) && !InsideCCAttribute) - OS << " __attribute__((arm_new_za))"; + OS << " __arm_new_za"; if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateZASharedMask) && !InsideCCAttribute) - OS << " __attribute__((arm_shared_za))"; + OS << " __arm_shared_za"; if ((T->getAArch64SMEAttributes() & FunctionType::SME_PStateZAPreservedMask) && !InsideCCAttribute) - OS << " __attribute__((arm_preserves_za))"; + OS << " __arm_preserves_za"; printFunctionAfter(Info, OS); 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 @@ -1653,30 +1653,43 @@ 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.isAttributeLikeKeyword()); // Consume the attributes. + auto Keyword = + Tok.isAttributeLikeKeyword() ? 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->isAttributeLikeKeyword() + ? 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->isAttributeLikeKeyword() + ? 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) { @@ -1696,13 +1709,18 @@ // 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.isAttributeLikeKeyword()) { + Diag(AL.getLoc(), KeywordDiagID) << AL; + AL.setInvalid(); + continue; + } if (!AL.isCXX11Attribute() && !AL.isC2xAttribute()) continue; if (AL.getKind() == ParsedAttr::UnknownAttribute) { @@ -1710,7 +1728,7 @@ Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL << AL.getRange(); } else { - Diag(AL.getLoc(), DiagID) << AL; + Diag(AL.getLoc(), AttrDiagID) << AL; AL.setInvalid(); } } @@ -1718,8 +1736,10 @@ 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.isAttributeLikeKeyword()) + Diag(PA.getLoc(), diag::ext_cxx11_attr_placement) + << PA.isAttributeLikeKeyword() << PA << PA.getRange(); } } @@ -1951,11 +1971,11 @@ return getLangOpts().CPlusPlus11 && isCXX11VirtSpecifier(NextToken()); default: - return false; + return Tok.isAttributeLikeKeyword(); } default: - return false; + return Tok.isAttributeLikeKeyword(); } } @@ -3244,13 +3264,17 @@ switch (Tok.getKind()) { default: + if (Tok.isAttributeLikeKeyword()) + 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.isAttributeLikeKeyword()) continue; if (PA.getKind() == ParsedAttr::UnknownAttribute) // We will warn about the unknown attribute elsewhere (in @@ -3269,7 +3293,8 @@ 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.isAttributeLikeKeyword(); PA.setInvalid(); } @@ -3283,9 +3308,10 @@ 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 @@ -4943,6 +4969,7 @@ 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) @@ -5087,7 +5114,7 @@ // 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 @@ -5779,8 +5806,8 @@ DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed, bool IdentifierRequired, Optional> CodeCompletionHandler) { - if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) && - isCXX11AttributeSpecifier()) { + if ((AttrReqs & AR_CXX11AttributesParsed) && + isAllowedCXX11AttributeSpecifier()) { ParsedAttributes Attrs(AttrFactory); ParseCXX11Attributes(Attrs); DS.takeAttributesFrom(Attrs); @@ -6546,6 +6573,10 @@ PrototypeScope.Exit(); } else if (Tok.is(tok::l_square)) { ParseBracketDeclarator(D); + } else if (Tok.isAttributeLikeKeyword()) { + // 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: @@ -6950,7 +6981,7 @@ 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 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -637,6 +637,7 @@ Tok.is(tok::identifier) && (NextToken().is(tok::semi) || NextToken().is(tok::comma) || NextToken().is(tok::ellipsis) || NextToken().is(tok::l_square) || + NextToken().isAttributeLikeKeyword() || NextToken().is(tok::kw___attribute)) && D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() && !D.SS.getScopeRep()->getAsNamespace() && @@ -769,11 +770,15 @@ // 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->isAttributeLikeKeyword() + ? 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); } @@ -1386,6 +1391,8 @@ // This switch enumerates the valid "follow" set for type-specifiers. switch (Tok.getKind()) { default: + if (Tok.isAttributeLikeKeyword()) + return true; break; case tok::semi: // struct foo {...} ; case tok::star: // struct foo {...} * P; @@ -1839,6 +1846,7 @@ } else if (isClassCompatibleKeyword() && (NextToken().is(tok::l_square) || NextToken().is(tok::kw_alignas) || + NextToken().isAttributeLikeKeyword() || 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. @@ -1860,6 +1868,8 @@ ConsumeParen(); if (!SkipUntil(tok::r_paren, StopAtSemi)) break; + } else if (Tok.isAttributeLikeKeyword()) { + ConsumeToken(); } else { break; } @@ -1896,7 +1906,11 @@ // 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->isAttributeLikeKeyword() + ? Diag(Loc, diag::err_keyword_not_allowed) << FirstAttr + : Diag(Loc, diag::err_attributes_not_allowed)) << AttrRange << FixItHint::CreateInsertionFromRange( AttrFixitLoc, CharSourceRange(AttrRange, true)) @@ -1944,6 +1958,7 @@ 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( @@ -1960,6 +1975,7 @@ (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, @@ -2029,6 +2045,7 @@ } 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( @@ -2039,6 +2056,7 @@ } 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 && @@ -3015,12 +3033,14 @@ // // 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.isAttributeLikeKeyword()) { + auto Loc = AL.getRange().getBegin(); + (AL.isAttributeLikeKeyword() + ? Diag(Loc, diag::err_keyword_not_allowed) << AL + : Diag(Loc, diag::err_attributes_not_allowed)) + << AL.getRange(); + } ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo, TemplateParams); @@ -4461,6 +4481,15 @@ return; } + if (Tok.isAttributeLikeKeyword()) { + SourceLocation Loc = Tok.getLocation(); + IdentifierInfo *AttrName = Tok.getIdentifierInfo(); + Attrs.addNew(AttrName, Loc, nullptr, Loc, nullptr, 0, + ParsedAttr::AS_AttributeLikeKeyword); + ConsumeToken(); + return; + } + assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) && "Not a double square bracket attribute list"); @@ -4579,26 +4608,30 @@ /// attribute-specifier-seq: /// attribute-specifier-seq[opt] attribute-specifier void Parser::ParseCXX11Attributes(ParsedAttributes &Attrs) { - assert(standardAttributesAllowed()); + assert(standardAttributesAllowed() || Tok.isAttributeLikeKeyword()); 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.isAttributeLikeKeyword() ? 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; } } @@ -4614,6 +4647,9 @@ T.consumeOpen(); T.skipToEnd(); EndLoc = T.getCloseLocation(); + } else if (Tok.isAttributeLikeKeyword()) { + 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 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -1359,9 +1359,16 @@ // or operator template declaration. We accept this as a conforming extension // in all language modes that support lambdas. if (isCXX11AttributeSpecifier()) { - Diag(Tok, getLangOpts().CPlusPlus2b - ? diag::warn_cxx20_compat_decl_attrs_on_lambda - : diag::ext_decl_attrs_on_lambda); + if (Tok.isAttributeLikeKeyword()) + Diag(Tok, getLangOpts().CPlusPlus2b + ? diag::warn_cxx20_compat_decl_attrs_on_lambda + : diag::ext_decl_attrs_on_lambda) + << 1 << Tok.getIdentifierInfo(); + else + Diag(Tok, getLangOpts().CPlusPlus2b + ? diag::warn_cxx20_compat_decl_attrs_on_lambda + : diag::ext_decl_attrs_on_lambda) + << 0 << ""; MaybeParseCXX11Attributes(D); } @@ -1490,6 +1497,7 @@ tok::kw___constant, tok::kw___generic, tok::kw_groupshared, tok::kw_requires, tok::kw_noexcept) || + Tok.isAttributeLikeKeyword() || (Tok.is(tok::l_square) && NextToken().is(tok::l_square))) { if (!getLangOpts().CPlusPlus2b) // It's common to forget that one needs '()' before 'mutable', an diff --git a/clang/lib/Parse/ParsePragma.cpp b/clang/lib/Parse/ParsePragma.cpp --- a/clang/lib/Parse/ParsePragma.cpp +++ b/clang/lib/Parse/ParsePragma.cpp @@ -1799,7 +1799,8 @@ ConsumeToken(); }; - if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) { + if ((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) || + Tok.isAttributeLikeKeyword()) { // 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 --- a/clang/lib/Parse/ParseStmt.cpp +++ b/clang/lib/Parse/ParseStmt.cpp @@ -333,7 +333,12 @@ case tok::kw_asm: { for (const ParsedAttr &AL : CXX11Attrs) - Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL; + // Could be relaxed if any statement attribute-like keywords are + // added later. + (AL.isAttributeLikeKeyword() + ? 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 --- a/clang/lib/Parse/ParseTentative.cpp +++ b/clang/lib/Parse/ParseTentative.cpp @@ -669,6 +669,9 @@ if (Tok.is(tok::kw_alignas)) return CAK_AttributeSpecifier; + if (Tok.isAttributeLikeKeyword()) + return CAK_AttributeSpecifier; + if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) return CAK_NotAttributeSpecifier; @@ -808,7 +811,8 @@ bool Parser::TrySkipAttributes() { while (Tok.isOneOf(tok::l_square, tok::kw___attribute, tok::kw___declspec, - tok::kw_alignas)) { + tok::kw_alignas) || + Tok.isAttributeLikeKeyword()) { if (Tok.is(tok::l_square)) { ConsumeBracket(); if (Tok.isNot(tok::l_square)) @@ -819,6 +823,8 @@ // 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.isAttributeLikeKeyword()) { + ConsumeToken(); } else { ConsumeToken(); if (Tok.isNot(tok::l_paren)) 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 @@ -2447,6 +2447,7 @@ ParsedAttributes Attrs(AttrFactory); MaybeParseCXX11Attributes(Attrs); ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr, + diag::err_keyword_not_module_attr, /*DiagnoseEmptyAttrs=*/false, /*WarnOnUnknownAttrs=*/true); @@ -2516,6 +2517,7 @@ 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 --- a/clang/lib/Sema/ParsedAttr.cpp +++ b/clang/lib/Sema/ParsedAttr.cpp @@ -213,6 +213,11 @@ } bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const { + if (isAttributeLikeKeyword()) + // The appurtenance rules are applied strictly for all attribute-like + // keywords. + 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 --- a/clang/lib/Sema/Sema.cpp +++ b/clang/lib/Sema/Sema.cpp @@ -1185,7 +1185,7 @@ !(isa(PrevDecl) || isa(PrevDecl))) for (const auto &WI : WeakIDs.second) Diag(WI.getLocation(), diag::warn_attribute_wrong_decl_type) - << "'weak'" << ExpectedVariableOrFunction; + << "'weak'" << 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 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -5306,12 +5306,18 @@ TypeSpecType == DeclSpec::TST_interface || TypeSpecType == DeclSpec::TST_union || TypeSpecType == DeclSpec::TST_enum) { - for (const ParsedAttr &AL : DS.getAttributes()) + for (const ParsedAttr &AL : DS.getAttributes()) { + assert(!AL.isAttributeLikeKeyword() && + "Failed to diagnose misplaced attribute-like keywords"); Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) << AL << GetDiagnosticTypeSpecifierID(TypeSpecType); - for (const ParsedAttr &AL : DeclAttrs) + } + for (const ParsedAttr &AL : DeclAttrs) { + assert(!AL.isAttributeLikeKeyword() && + "Failed to diagnose misplaced attribute-like keywords"); Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored) << AL << GetDiagnosticTypeSpecifierID(TypeSpecType); + } } } 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 @@ -273,7 +273,9 @@ 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.isAttributeLikeKeyword() || A->isAttributeLikeKeyword()); S.Diag(A->getLocation(), diag::note_conflicting_attribute); return true; } @@ -283,8 +285,9 @@ 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.isAttributeLikeKeyword() || A->isAttributeLikeKeyword()); S.Diag(A->getLocation(), diag::note_conflicting_attribute); return true; } @@ -1878,7 +1881,9 @@ // 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; + S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) + << AL << I + << (AL.isAttributeLikeKeyword() || I->isAttributeLikeKeyword()); return; } else if (K == OwnershipAttr::Returns && I->getOwnKind() == OwnershipAttr::Returns) { @@ -2164,7 +2169,7 @@ // 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 << 0 << "non-member functions"; return; } } @@ -2177,7 +2182,7 @@ if (!isa(D)) { S.Diag(Attrs.getLoc(), diag::warn_attribute_wrong_decl_type) - << Attrs << ExpectedFunctionOrMethod; + << Attrs << 0 << ExpectedFunctionOrMethod; return; } @@ -2218,7 +2223,9 @@ 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.isAttributeLikeKeyword() + ? diag::err_keyword_not_supported_on_target + : diag::warn_unknown_attribute_ignored) << AL << AL.getRange(); AL.setInvalid(); return true; @@ -2235,10 +2242,11 @@ ValueDecl *VD = dyn_cast(D); if (!VD || (!VD->getType()->isBlockPointerType() && !VD->getType()->isFunctionPointerType())) { - S.Diag(AL.getLoc(), AL.isStandardAttributeSyntax() - ? diag::err_attribute_wrong_decl_type - : diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionMethodOrBlock; + S.Diag(AL.getLoc(), + (AL.isStandardAttributeSyntax() || AL.isAttributeLikeKeyword() + ? diag::err_attribute_wrong_decl_type + : diag::warn_attribute_wrong_decl_type)) + << AL << 0 << ExpectedFunctionMethodOrBlock; return; } } @@ -2884,12 +2892,10 @@ } // '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 << 0 << ExpectedTypeOrNamespace; return; } @@ -3108,12 +3114,12 @@ } } else { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionMethodOrBlock; + << AL << 0 << ExpectedFunctionMethodOrBlock; return; } } else { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionMethodOrBlock; + << AL << 0 << ExpectedFunctionMethodOrBlock; return; } D->addAttr(::new (S.Context) SentinelAttr(S.Context, AL, sentinel, nullPos)); @@ -3138,7 +3144,7 @@ // as a function pointer. if (isa(D)) S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << AL << "functions, classes, or enumerations"; + << AL << 0 << "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, @@ -3184,7 +3190,7 @@ // Nothing to warn about here. } else S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedVariableOrFunction; + << AL << 0 << ExpectedVariableOrFunction; return; } @@ -3781,7 +3787,7 @@ (EA->isWarning() && NewAttr == "warning"); if (!Match) { Diag(EA->getLocation(), diag::err_attributes_are_not_compatible) - << CI << EA; + << CI << EA << 0; Diag(CI.getLoc(), diag::note_conflicting_attribute); return nullptr; } @@ -4087,8 +4093,8 @@ 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 << 0 << ExpectedUnion; return; } @@ -4279,9 +4285,10 @@ if (ED->getLangOpts().CPlusPlus) DiagKind = 4; } else if (!isa(D)) { - Diag(AttrLoc, diag::err_attribute_wrong_decl_type) << &TmpAttr - << (TmpAttr.isC11() ? ExpectedVariableOrField - : ExpectedVariableFieldOrTag); + Diag(AttrLoc, diag::err_attribute_wrong_decl_type) + << &TmpAttr << 0 + << (TmpAttr.isC11() ? ExpectedVariableOrField + : ExpectedVariableFieldOrTag); return; } if (DiagKind != -1) { @@ -4704,8 +4711,9 @@ // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass - : ExpectedVariableOrFunction); + << AL << 0 + << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); return nullptr; } // Attribute does not apply to non-static local variables. @@ -4724,8 +4732,9 @@ // ImplicitParm or VarTemplateSpecialization). if (VD->getKind() != Decl::Var) { Diag(AL.getLocation(), diag::warn_attribute_wrong_decl_type) - << &AL << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass - : ExpectedVariableOrFunction); + << &AL << 0 + << (getLangOpts().CPlusPlus ? ExpectedFunctionVariableOrClass + : ExpectedVariableOrFunction); return nullptr; } // Attribute does not apply to non-static local variables. @@ -4756,7 +4765,7 @@ 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 << 0; Diag(SNA.getLoc(), diag::note_conflicting_attribute); } @@ -4918,7 +4927,7 @@ if (!isa(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionOrMethod; + << AL << AL.isAttributeLikeKeyword() << ExpectedFunctionOrMethod; return; } @@ -5049,7 +5058,7 @@ : nullptr; if (ExistingDerefType != ParmType.getTypePtrOrNull()) { S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) - << AL << OAttr; + << AL << OAttr << 0; S.Diag(OAttr->getLocation(), diag::note_conflicting_attribute); } return; @@ -5066,7 +5075,7 @@ : nullptr; if (ExistingDerefType != ParmType.getTypePtrOrNull()) { S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible) - << AL << PAttr; + << AL << PAttr << 0; S.Diag(PAttr->getLocation(), diag::note_conflicting_attribute); } return; @@ -5298,7 +5307,7 @@ if (auto existingAttr = D->getAttr()) { if (existingAttr->getABI() != abi) { Diag(CI.getLoc(), diag::err_attributes_are_not_compatible) - << getParameterABISpelling(abi) << existingAttr; + << getParameterABISpelling(abi) << existingAttr << 0; Diag(existingAttr->getLocation(), diag::note_conflicting_attribute); return; } @@ -5490,7 +5499,7 @@ if (!isa(D)) { S.Diag(AL.getLoc(), diag::err_attribute_wrong_decl_type) - << AL << ExpectedVariable; + << AL << 0 << ExpectedVariable; return; } @@ -5787,7 +5796,7 @@ break; } S.Diag(D->getBeginLoc(), diag::warn_attribute_wrong_decl_type) - << AL.getRange() << AL << ExpectedDeclKind; + << AL.getRange() << AL << 0 << ExpectedDeclKind; return; } @@ -6059,10 +6068,11 @@ } 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 << 0 << ExpectedVariable; } static void handleObjCPreciseLifetimeAttr(Sema &S, Decl *D, @@ -6555,8 +6565,8 @@ Params = F->parameters(); if (!F->hasWrittenPrototype()) { - Diag(Loc, diag::warn_attribute_wrong_decl_type) << AL - << ExpectedFunctionWithProtoType; + Diag(Loc, diag::warn_attribute_wrong_decl_type) + << AL << 0 << ExpectedFunctionWithProtoType; return false; } } @@ -6676,7 +6686,7 @@ if (!isa(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type_str) - << AL << "typedefs"; + << AL << 0 << "typedefs"; return; } @@ -7151,7 +7161,7 @@ // a function with no parameters and void return type. if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'interrupt'" << ExpectedFunctionOrMethod; + << "'interrupt'" << 0 << ExpectedFunctionOrMethod; return; } @@ -7224,7 +7234,7 @@ if (!isFunctionOrMethod(D)) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'interrupt'" << ExpectedFunctionOrMethod; + << "'interrupt'" << 0 << ExpectedFunctionOrMethod; return; } @@ -7299,7 +7309,7 @@ CXXMethodDecl::isStaticOverloadedOperator( cast(D)->getDeclName().getCXXOverloadedOperator())) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunctionWithProtoType; + << AL << 0 << ExpectedFunctionWithProtoType; return; } // Interrupt handler must have void return type. @@ -7355,7 +7365,7 @@ 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; + << "'interrupt'" << 0 << ExpectedFunction; return; } @@ -7368,7 +7378,7 @@ 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; + << "'signal'" << 0 << ExpectedFunction; return; } @@ -7421,10 +7431,11 @@ 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; + << "'export_name'" << 0 << ExpectedFunction; return; } @@ -7548,7 +7559,7 @@ if (D->getFunctionType() == nullptr) { S.Diag(D->getLocation(), diag::warn_attribute_wrong_decl_type) - << "'interrupt'" << ExpectedFunction; + << "'interrupt'" << 0 << ExpectedFunction; return; } @@ -7743,7 +7754,7 @@ // Attribute can only be applied to function types. if (!isa(D)) { S.Diag(AL.getLoc(), diag::warn_attribute_wrong_decl_type) - << AL << ExpectedFunction; + << AL << 0 << ExpectedFunction; return; } @@ -8022,7 +8033,7 @@ .Case("no_sanitize_memory", "memory"); if (isGlobalVar(D) && SanitizerName != "address") S.Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << AL << ExpectedFunction; + << AL << 0 << ExpectedFunction; // FIXME: Rather than create a NoSanitizeSpecificAttr, this creates a // NoSanitizeAttr object; but we need to calculate the correct spelling list @@ -8484,7 +8495,9 @@ if (AL.getKind() == ParsedAttr::UnknownAttribute || !AL.existsInTarget(S.Context.getTargetInfo())) { S.Diag(AL.getLoc(), - AL.isDeclspecAttribute() + AL.isAttributeLikeKeyword() + ? (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(); @@ -8513,7 +8526,7 @@ if (AL.isTypeAttr()) { if (Options.IgnoreTypeAttributes) break; - if (!AL.isStandardAttributeSyntax()) { + if (!AL.isStandardAttributeSyntax() && !AL.isAttributeLikeKeyword()) { // Non-[[]] type attributes are handled in processTypeAttrs(); silently // move on. break; @@ -8578,7 +8591,7 @@ // 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.isAttributeLikeKeyword() << D->getLocation(); break; case ParsedAttr::AT_Interrupt: handleInterruptAttr(S, D, AL); @@ -9282,19 +9295,19 @@ } else if (!D->hasAttr()) { if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << 0 << ExpectedKernelFunction; D->setInvalidDecl(); } else if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << 0 << ExpectedKernelFunction; D->setInvalidDecl(); } else if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << 0 << ExpectedKernelFunction; D->setInvalidDecl(); } else if (const auto *A = D->getAttr()) { Diag(D->getLocation(), diag::err_attribute_wrong_decl_type) - << A << ExpectedKernelFunction; + << A << 0 << ExpectedKernelFunction; D->setInvalidDecl(); } } @@ -9358,8 +9371,8 @@ S.Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored) << AL << AL.getRange(); } else { - S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) << AL - << AL.getRange(); + S.Diag(AL.getLoc(), diag::warn_attribute_not_on_decl) + << AL << AL.getRange(); } } } 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 @@ -2709,10 +2709,12 @@ 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.isAttributeLikeKeyword() << AL.getRange(); } TypeSourceInfo *TInfo = nullptr; diff --git a/clang/lib/Sema/SemaStmtAttr.cpp b/clang/lib/Sema/SemaStmtAttr.cpp --- a/clang/lib/Sema/SemaStmtAttr.cpp +++ b/clang/lib/Sema/SemaStmtAttr.cpp @@ -458,7 +458,9 @@ !(A.existsInTarget(S.Context.getTargetInfo()) || (S.Context.getLangOpts().SYCLIsDevice && Aux && A.existsInTarget(*Aux)))) { - S.Diag(A.getLoc(), A.isDeclspecAttribute() + S.Diag(A.getLoc(), A.isAttributeLikeKeyword() + ? (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(); @@ -494,7 +496,7 @@ // 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.isAttributeLikeKeyword() << St->getBeginLoc(); return nullptr; } } 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 @@ -101,8 +101,10 @@ } } - S.Diag(loc, diag::warn_type_attribute_wrong_type) << name << WhichType - << type; + S.Diag(loc, attr.isAttributeLikeKeyword() + ? 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 @@ -687,7 +689,7 @@ for (ParsedAttr &attr : AttrsCopy) { // Do not distribute [[]] attributes. They have strict rules for what // they appertain to. - if (attr.isStandardAttributeSyntax()) + if (attr.isStandardAttributeSyntax() || attr.isAttributeLikeKeyword()) continue; switch (attr.getKind()) { @@ -7270,12 +7272,12 @@ if (Attrs[attr::Ptr32] && Attrs[attr::Ptr64]) { S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) << "'__ptr32'" - << "'__ptr64'"; + << "'__ptr64'" << 0; return true; } else if (Attrs[attr::SPtr] && Attrs[attr::UPtr]) { S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible) << "'__sptr'" - << "'__uptr'"; + << "'__uptr'" << 0; return true; } @@ -7659,7 +7661,8 @@ Sema &S = state.getSema(); S.Diag(Attr.getLoc(), diag::err_attributes_are_not_compatible) - << *OtherAttr << Attr; + << *OtherAttr << Attr + << (OtherAttr->isAttributeLikeKeyword() || Attr.isAttributeLikeKeyword()); S.Diag(OtherAttr->getLoc(), diag::note_conflicting_attribute); Attr.setInvalid(); return true; @@ -7782,8 +7785,7 @@ 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" << 0; attr.setInvalid(); return true; } @@ -7921,8 +7923,8 @@ // 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) << 0; attr.setInvalid(); return true; } @@ -7954,7 +7956,7 @@ // 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) << 0; attr.setInvalid(); return true; } @@ -8408,12 +8410,13 @@ if (attr.isInvalid()) continue; - if (attr.isStandardAttributeSyntax()) { + if (attr.isStandardAttributeSyntax() || attr.isAttributeLikeKeyword()) { // [[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(), @@ -8441,9 +8444,10 @@ 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.isAttributeLikeKeyword()) && + TAL == TAL_DeclChunk) { state.getSema().Diag(attr.getLoc(), diag::err_attribute_not_type_attr) - << attr; + << attr << attr.isAttributeLikeKeyword(); attr.setUsedAsTypeAttr(); } break; @@ -8614,7 +8618,7 @@ // 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.isAttributeLikeKeyword()) { if (!handleFunctionTypeAttr(state, attr, type)) { diagnoseBadTypeAttribute(state.getSema(), attr, type); attr.setInvalid(); diff --git a/clang/test/AST/ast-dump-sme-attributes.cpp b/clang/test/AST/ast-dump-sme-attributes.cpp --- a/clang/test/AST/ast-dump-sme-attributes.cpp +++ b/clang/test/AST/ast-dump-sme-attributes.cpp @@ -9,19 +9,19 @@ struct Foo { // CHECK: |-CXXRecordDecl {{.*}} implicit struct Foo -// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_streaming 'void () __attribute__((arm_streaming))' -// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_streaming_compatible 'void () __attribute__((arm_streaming_compatible))' +// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_streaming 'void () __arm_streaming' +// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_streaming_compatible 'void () __arm_streaming_compatible' // CHECK-NEXT: |-CXXMethodDecl {{.*}} f_locally_streaming 'void ()' // CHECK-NEXT: | `-ArmLocallyStreamingAttr {{.*}} -// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_shared_za 'void () __attribute__((arm_shared_za))' -// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_new_za 'void () __attribute__((arm_new_za))' -// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_preserves_za 'void () __attribute__((arm_preserves_za))' - void f_streaming() __attribute__((arm_streaming)); - void f_streaming_compatible() __attribute__((arm_streaming_compatible)); - void f_locally_streaming() __attribute__((arm_locally_streaming)); - void f_shared_za() __attribute__((arm_shared_za)); - void f_new_za() __attribute__((arm_new_za)); - void f_preserves_za() __attribute__((arm_preserves_za)); +// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_shared_za 'void () __arm_shared_za' +// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_new_za 'void () __arm_new_za' +// CHECK-NEXT: |-CXXMethodDecl {{.*}} f_preserves_za 'void () __arm_preserves_za' + void f_streaming() __arm_streaming; + void f_streaming_compatible() __arm_streaming_compatible; + __arm_locally_streaming void f_locally_streaming(); + void f_shared_za() __arm_shared_za; + void f_new_za() __arm_new_za; + void f_preserves_za() __arm_preserves_za; // CHECK: |-CXXMethodDecl {{.*}} test_lambda 'int (int)' implicit-inline @@ -30,33 +30,33 @@ // CHECK-NEXT: | `-VarDecl // CHECK-NEXT: | `-LambdaExpr // CHECK-NEXT: | |-CXXRecordDecl -// CHECK: | | |-CXXMethodDecl {{.*}} used constexpr operator() 'int (int) __attribute__((arm_streaming)) const' inline -// CHECK: | | |-CXXConversionDecl {{.*}} implicit constexpr operator int (*)(int) __attribute__((arm_streaming)) 'int (*() const noexcept)(int) __attribute__((arm_streaming))' inline -// CHECK: | | |-CXXMethodDecl {{.*}} implicit __invoke 'int (int) __attribute__((arm_streaming))' static inline +// CHECK: | | |-CXXMethodDecl {{.*}} used constexpr operator() 'int (int) __arm_streaming const' inline +// CHECK: | | |-CXXConversionDecl {{.*}} implicit constexpr operator int (*)(int) __arm_streaming 'int (*() const noexcept)(int) __arm_streaming' inline +// CHECK: | | |-CXXMethodDecl {{.*}} implicit __invoke 'int (int) __arm_streaming' static inline // CHECK: `-ReturnStmt // CHECK: `-CXXOperatorCallExpr -// CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int (*)(int) __attribute__((arm_streaming)) const' -// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int (int) __attribute__((arm_streaming)) const' lvalue CXXMethod {{.*}} 'operator()' 'int (int) __attribute__((arm_streaming)) const' +// CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int (*)(int) __arm_streaming const' +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int (int) __arm_streaming const' lvalue CXXMethod {{.*}} 'operator()' 'int (int) __arm_streaming const' int test_lambda(int x) { - auto F = [](int x) __attribute__((arm_streaming)) { return x; }; + auto F = [](int x) __arm_streaming { return x; }; return F(x); } -// CHECK: |-TypedefDecl {{.*}} referenced s_ptrty 'void (*)(int, int) __attribute__((arm_streaming))' -// CHECK-NEXT: | `-PointerType {{.*}} 'void (*)(int, int) __attribute__((arm_streaming))' -// CHECK-NEXT: | `-ParenType {{.*}} 'void (int, int) __attribute__((arm_streaming))' sugar -// CHECK-NEXT: | `-FunctionProtoType {{.*}} 'void (int, int) __attribute__((arm_streaming))' cdecl - typedef void __attribute__((arm_streaming)) (*s_ptrty) (int, int); +// CHECK: |-TypedefDecl {{.*}} referenced s_ptrty 'void (*)(int, int) __arm_streaming' +// CHECK-NEXT: | `-PointerType {{.*}} 'void (*)(int, int) __arm_streaming' +// CHECK-NEXT: | `-ParenType {{.*}} 'void (int, int) __arm_streaming' sugar +// CHECK-NEXT: | `-FunctionProtoType {{.*}} 'void (int, int) __arm_streaming' cdecl + typedef void (*__arm_streaming s_ptrty) (int, int); // CHECK: `-CXXMethodDecl {{.*}} test_streaming_ptrty 'void (s_ptrty, int, int)' implicit-inline -// CHECK-NEXT: |-ParmVarDecl {{.*}} used f 's_ptrty':'void (*)(int, int) __attribute__((arm_streaming))' +// CHECK-NEXT: |-ParmVarDecl {{.*}} used f 's_ptrty':'void (*)(int, int) __arm_streaming' // CHECK-NEXT: |-ParmVarDecl {{.*}} used x 'int' // CHECK-NEXT: |-ParmVarDecl {{.*}} used y 'int' // CHECK: `-CompoundStmt // CHECK-NEXT: `-ReturnStmt // CHECK-NEXT: `-CallExpr -// CHECK-NEXT: |-ImplicitCastExpr {{.*}} 's_ptrty':'void (*)(int, int) __attribute__((arm_streaming))' -// CHECK-NEXT: | `-DeclRefExpr {{.*}} 's_ptrty':'void (*)(int, int) __attribute__((arm_streaming))' lvalue ParmVar {{.*}} 'f' 's_ptrty':'void (*)(int, int) __attribute__((arm_streaming))' +// CHECK-NEXT: |-ImplicitCastExpr {{.*}} 's_ptrty':'void (*)(int, int) __arm_streaming' +// CHECK-NEXT: | `-DeclRefExpr {{.*}} 's_ptrty':'void (*)(int, int) __arm_streaming' lvalue ParmVar {{.*}} 'f' 's_ptrty':'void (*)(int, int) __arm_streaming' // CHECK-NEXT: |-ImplicitCastExpr {{.*}} 'int' // CHECK-NEXT: | `-DeclRefExpr {{.*}} 'int' lvalue ParmVar {{.*}} 'x' 'int' // CHECK-NEXT: `-ImplicitCastExpr {{.*}} 'int' diff --git a/clang/test/CXX/modules-ts/basic/basic.link/module-declaration.cpp b/clang/test/CXX/modules-ts/basic/basic.link/module-declaration.cpp --- a/clang/test/CXX/modules-ts/basic/basic.link/module-declaration.cpp +++ b/clang/test/CXX/modules-ts/basic/basic.link/module-declaration.cpp @@ -30,6 +30,8 @@ // RUN: -DTEST=9 -DEXPORT=export -DMODULE_NAME='z [[fancy]]' // RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \ // RUN: -DTEST=10 -DEXPORT=export -DMODULE_NAME='z [[maybe_unused]]' +// RUN: %clang_cc1 -std=c++1z -fmodules-ts -I%t -fmodule-file=%t/x.y.pcm -verify %s \ +// RUN: -DTEST=11 -DEXPORT=export -DMODULE_NAME='z __arm_streaming' EXPORT module MODULE_NAME; #if TEST == 4 @@ -43,6 +45,8 @@ // expected-error-re@-9 {{'maybe_unused' attribute cannot be applied to a module{{$}}}} #elif TEST == 1 // expected-error@-11 {{definition of module 'z' is not available}} +#elif TEST == 11 +// expected-error-re@-13 {{'__arm_streaming' cannot be applied to a module{{$}}}} #else // expected-no-diagnostics #endif diff --git a/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp b/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp --- a/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp +++ b/clang/test/CXX/modules-ts/dcl.dcl/dcl.module/dcl.module.import/p1.cpp @@ -38,6 +38,7 @@ import x [[foo]]; // expected-warning {{unknown attribute 'foo' ignored}} import x [[noreturn]]; // expected-error {{'noreturn' attribute cannot be applied to a module import}} import x [[blarg::noreturn]]; // expected-warning {{unknown attribute 'noreturn' ignored}} +import x __arm_streaming; // expected-error {{'__arm_streaming' cannot be applied to a module import}} import x.y; import a.b; // Does not imply existence of module a. diff --git a/clang/test/CodeGen/aarch64-sme-intrinsics/aarch64-sme-attrs.cpp b/clang/test/CodeGen/aarch64-sme-intrinsics/aarch64-sme-attrs.cpp --- a/clang/test/CodeGen/aarch64-sme-intrinsics/aarch64-sme-attrs.cpp +++ b/clang/test/CodeGen/aarch64-sme-intrinsics/aarch64-sme-attrs.cpp @@ -7,11 +7,11 @@ // == FUNCTION DECLARATIONS == -__attribute__((arm_streaming)) int streaming_decl(); -__attribute__((arm_streaming_compatible)) int streaming_compatible_decl(); -__attribute__((arm_shared_za)) int shared_za_decl(); -__attribute__((arm_preserves_za)) int preserves_za_decl(); -__attribute__((arm_new_za)) int new_za_decl(); +int streaming_decl() __arm_streaming; +int streaming_compatible_decl() __arm_streaming_compatible; +int shared_za_decl() __arm_shared_za; +int preserves_za_decl() __arm_preserves_za; +int new_za_decl() __arm_new_za; // == FUNCTION DEFINITIONS == @@ -19,7 +19,7 @@ // CHECK-SAME: #[[SM_ENABLED:[0-9]+]] // CHECK: call i32 @normal_callee() // -__attribute__((arm_streaming)) int streaming_caller() { +int streaming_caller() __arm_streaming { return normal_callee(); } @@ -30,7 +30,7 @@ // CHECK-SAME: #[[SM_ENABLED]] // CHECK: call i32 @streaming_decl() #[[SM_ENABLED_CALL:[0-9]+]] // -__attribute__((arm_streaming)) int streaming_callee() { +int streaming_callee() __arm_streaming { return streaming_decl(); } @@ -40,7 +40,7 @@ // CHECK-SAME: #[[SM_COMPATIBLE:[0-9]+]] // CHECK: call i32 @normal_callee() // -__attribute__((arm_streaming_compatible)) int streaming_compatible_caller() { +int streaming_compatible_caller() __arm_streaming_compatible { return normal_callee(); } @@ -48,7 +48,7 @@ // CHECK-SAME: #[[SM_COMPATIBLE]] // CHECK: call i32 @streaming_compatible_decl() #[[SM_COMPATIBLE_CALL:[0-9]+]] // -__attribute__((arm_streaming_compatible)) int streaming_compatible_callee() { +int streaming_compatible_callee() __arm_streaming_compatible { return streaming_compatible_decl(); } @@ -58,7 +58,7 @@ // CHECK-SAME: #[[SM_BODY:[0-9]+]] // CHECK: call i32 @normal_callee() // -__attribute__((arm_locally_streaming)) int locally_streaming_caller() { +__arm_locally_streaming int locally_streaming_caller() { return normal_callee(); } @@ -66,7 +66,7 @@ // CHECK-SAME: #[[SM_BODY]] // CHECK: call i32 @locally_streaming_caller() #[[SM_BODY_CALL:[0-9]+]] // -__attribute__((arm_locally_streaming)) int locally_streaming_callee() { +__arm_locally_streaming int locally_streaming_callee() { return locally_streaming_caller(); } @@ -75,7 +75,7 @@ // CHECK-SAME: #[[ZA_SHARED:[0-9]+]] // CHECK: call i32 @normal_callee() // -__attribute__((arm_shared_za)) int shared_za_caller() { +int shared_za_caller() __arm_shared_za { return normal_callee(); } @@ -83,7 +83,7 @@ // CHECK-SAME: #[[ZA_SHARED]] // CHECK: call i32 @shared_za_decl() #[[ZA_SHARED_CALL:[0-9]+]] // -__attribute__((arm_shared_za)) int shared_za_callee() { +int shared_za_callee() __arm_shared_za { return shared_za_decl(); } @@ -94,7 +94,7 @@ // CHECK-SAME: #[[ZA_PRESERVED:[0-9]+]] // CHECK: call i32 @normal_callee() // -__attribute__((arm_preserves_za)) int preserves_za_caller() { +int preserves_za_caller() __arm_preserves_za { return normal_callee(); } @@ -102,7 +102,7 @@ // CHECK-SAME: #[[ZA_PRESERVED]] // CHECK: call i32 @preserves_za_decl() #[[ZA_PRESERVED_CALL:[0-9]+]] // -__attribute__((arm_preserves_za)) int preserves_za_callee() { +int preserves_za_callee() __arm_preserves_za { return preserves_za_decl(); } @@ -113,7 +113,7 @@ // CHECK-SAME: #[[ZA_NEW:[0-9]+]] // CHECK: call i32 @normal_callee() // -__attribute__((arm_new_za)) int new_za_caller() { +int new_za_caller() __arm_new_za { return normal_callee(); } @@ -121,7 +121,7 @@ // CHECK-SAME: #[[ZA_NEW]] // CHECK: call i32 @new_za_decl() #[[ZA_NEW_CALL:[0-9]+]] // -__attribute__((arm_new_za)) int new_za_callee() { +int new_za_callee() __arm_new_za { return new_za_decl(); } @@ -130,11 +130,11 @@ // Ensure that the attributes are correctly propagated to function types // and also to callsites. -typedef void __attribute__((arm_streaming)) (*s_ptrty) (int, int); -typedef void __attribute__((arm_streaming_compatible)) (*sc_ptrty) (int, int); -typedef void __attribute__((arm_new_za)) (*nz_ptrty) (int, int); -typedef void __attribute__((arm_shared_za)) (*sz_ptrty) (int, int); -typedef void __attribute__((arm_preserves_za)) (*pz_ptrty) (int, int); +typedef void (*__arm_streaming s_ptrty) (int, int); +typedef void (*__arm_streaming_compatible sc_ptrty) (int, int); +typedef void (*__arm_new_za nz_ptrty) (int, int); +typedef void (*__arm_shared_za sz_ptrty) (int, int); +typedef void (*__arm_preserves_za pz_ptrty) (int, int); // CHECK-LABEL: @test_streaming_ptrty( // CHECK-SAME: #[[NORMAL_DEF:[0-9]+]] @@ -150,17 +150,17 @@ // CHECK-SAME: #[[ZA_SHARED]] // CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ZA_NEW_CALL]] // -void __attribute__((arm_shared_za)) test_new_za(nz_ptrty f, int x, int y) { return f(x, y); } +void test_new_za(nz_ptrty f, int x, int y) __arm_shared_za { return f(x, y); } // CHECK-LABEL: @test_shared_za( // CHECK-SAME: #[[ZA_SHARED]] // CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ZA_SHARED_CALL]] // -void __attribute__((arm_shared_za)) test_shared_za(sz_ptrty f, int x, int y) { return f(x, y); } +void test_shared_za(sz_ptrty f, int x, int y) __arm_shared_za { return f(x, y); } // CHECK-LABEL: @test_preserved_za( // CHECK-SAME: #[[ZA_SHARED]] // CHECK: call void [[F:%.*]](i32 noundef [[X:%.*]], i32 noundef [[Y:%.*]]) #[[ZA_PRESERVED_CALL]] // -void __attribute__((arm_shared_za)) test_preserved_za(pz_ptrty f, int x, int y) { return f(x, y); } +void test_preserved_za(pz_ptrty f, int x, int y) __arm_shared_za { return f(x, y); } // CHECK-LABEL: @test_indirect_streaming_ptrty( // CHECK-SAME: #[[NORMAL_DEF:[0-9]+]] @@ -190,9 +190,9 @@ // CHECK: declare void @_Z20same_type_streaming1v() #[[SM_ENABLED_DECL]] // CHECK: declare void @_Z20same_type_streaming2v() #[[SM_ENABLED_DECL]] // CHECK: declare void @_Z20same_type_streaming3v() #[[SM_ENABLED_DECL]] -__attribute__((arm_streaming)) void streaming1(); -void __attribute__((arm_streaming)) streaming2(); -void streaming3() __attribute__((arm_streaming)); +void streaming1() __arm_streaming; +void streaming2() __arm_streaming; +void streaming3() __arm_streaming; decltype(streaming1) same_type_streaming1; decltype(streaming2) same_type_streaming2; decltype(streaming3) same_type_streaming3; @@ -212,7 +212,7 @@ // CHECK-LABEL: @_Z12overloadedfni( // CHECK-SAME: #[[SM_ENABLED]] -int __attribute__((arm_streaming)) overloadedfn(int x) { return x; } +int overloadedfn(int x) __arm_streaming { return x; } // CHECK-LABEL: @_Z12overloadedfnf( // CHECK-SAME: #[[NORMAL_DEF]] // @@ -233,7 +233,7 @@ // CHECK: @"_ZZ11test_lambdaiENK3$_0clEi"( // CHECK-SAME: #[[SM_ENABLED]] int test_lambda(int x) { - auto F = [](int x) __attribute__((arm_streaming)) { return x; }; + auto F = [](int x) __arm_streaming { return x; }; return F(x); } @@ -244,7 +244,7 @@ // CHECK: @_Z15template_functyIiET_S0_( // CHECK-SAME: #[[SM_ENABLED]] template -Ty template_functy(Ty x) __attribute__((arm_streaming)) { return x; } +Ty template_functy(Ty x) __arm_streaming { return x; } int test_template_instantiation() { return template_functy(12); } // @@ -254,7 +254,7 @@ // CHECK: define {{.*}} @_Z25locally_streaming_inheritv( // CHECK-SAME: #[[SM_BODY]] -__attribute__((arm_locally_streaming)) void locally_streaming_inherit(); +__arm_locally_streaming void locally_streaming_inherit(); void locally_streaming_inherit() { streaming_decl(); } diff --git a/clang/test/Misc/pragma-attribute-supported-attributes-list.test b/clang/test/Misc/pragma-attribute-supported-attributes-list.test --- a/clang/test/Misc/pragma-attribute-supported-attributes-list.test +++ b/clang/test/Misc/pragma-attribute-supported-attributes-list.test @@ -18,7 +18,6 @@ // CHECK-NEXT: AnyX86NoCfCheck (SubjectMatchRule_hasType_functionType) // CHECK-NEXT: ArcWeakrefUnavailable (SubjectMatchRule_objc_interface) // CHECK-NEXT: ArmBuiltinAlias (SubjectMatchRule_function) -// CHECK-NEXT: ArmLocallyStreaming (SubjectMatchRule_function) // CHECK-NEXT: AssumeAligned (SubjectMatchRule_objc_method, SubjectMatchRule_function) // CHECK-NEXT: Assumption (SubjectMatchRule_function, SubjectMatchRule_objc_method) // CHECK-NEXT: Availability ((SubjectMatchRule_record, SubjectMatchRule_enum, SubjectMatchRule_enum_constant, SubjectMatchRule_field, SubjectMatchRule_function, SubjectMatchRule_namespace, SubjectMatchRule_objc_category, SubjectMatchRule_objc_implementation, SubjectMatchRule_objc_interface, SubjectMatchRule_objc_method, SubjectMatchRule_objc_property, SubjectMatchRule_objc_protocol, SubjectMatchRule_record, SubjectMatchRule_type_alias, SubjectMatchRule_variable)) diff --git a/clang/test/Parser/c2x-attribute-keywords.c b/clang/test/Parser/c2x-attribute-keywords.c new file mode 100644 --- /dev/null +++ b/clang/test/Parser/c2x-attribute-keywords.c @@ -0,0 +1,118 @@ +// 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' only applies to}} + One __arm_streaming, // expected-error {{'__arm_streaming' only applies to}} + Two, + Three __arm_streaming // expected-error {{'__arm_streaming' only applies to}} +}; + +enum __arm_streaming { Four }; // expected-error {{'__arm_streaming' only applies to}} +__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' only applies to}} + 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' only applies to}} + +union __arm_streaming U { // expected-error {{'__arm_streaming' only applies to}} + double d __arm_streaming; // expected-error {{'__arm_streaming' only applies to}} + __arm_streaming int i; // expected-error {{'__arm_streaming' only applies to}} +}; + +__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' only applies to}} + +struct __arm_streaming IncompleteStruct; // expected-error {{'__arm_streaming' only applies to}} +union __arm_streaming IncompleteUnion; // expected-error {{'__arm_streaming' only applies to}} +enum __arm_streaming IncompleteEnum; // expected-error {{'__arm_streaming' only applies to}} + +__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' only applies to}} + + __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 2 {{'__arm_streaming' only applies to}} + + __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 --- /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' only applies to}} + +@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-attribute-keywords.cpp b/clang/test/Parser/cxx0x-attribute-keywords.cpp new file mode 100644 --- /dev/null +++ b/clang/test/Parser/cxx0x-attribute-keywords.cpp @@ -0,0 +1,339 @@ +// 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 -target-feature +sme %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' only applies to}} +class __arm_streaming class_attr {}; // expected-error {{'__arm_streaming' only applies to}} +union __arm_streaming union_attr; // expected-error {{'__arm_streaming' only applies to}} +enum __arm_streaming E { }; // expected-error {{'__arm_streaming' only applies to}} +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' only applies to}} + attr_after_class_name_decl __arm_streaming __arm_streaming; // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error 2 {{'__arm_streaming' only applies to}} + +class __arm_streaming __arm_streaming // expected-error 2 {{'__arm_streaming' only applies to}} + attr_after_class_name_definition __arm_streaming __arm_streaming __arm_streaming{}; // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error 3 {{'__arm_streaming' only applies to}} + +class __arm_streaming c {}; // expected-error {{'__arm_streaming' only applies to}} +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' only applies to}} + __arm_streaming alignas(float) final // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error {{'__arm_streaming' only applies to}} + __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' only applies to}} + __arm_streaming __arm_streaming alignas(16) final // expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error 2 {{'__arm_streaming' only applies to}} + __arm_streaming __arm_streaming alignas(16) __arm_streaming{}; // expected-error {{'__arm_streaming' cannot appear here}} + +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' only applies to}} +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' only applies to}} +__arm_streaming using namespace ns; // expected-error {{'__arm_streaming' only applies to}} +namespace __arm_streaming ns2 {} // expected-warning {{attributes on a namespace declaration are a C++17 extension}} \ + expected-error {{'__arm_streaming' only applies to}} + +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' only applies to}} +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' only applies to}} +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' only applies to}} +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' only applies to}} + using using_in_struct_base::j __arm_streaming; // expected-warning {{ISO C++}} \ + expected-error {{'__arm_streaming' only applies to}} + __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' only applies to}} +}; +using __arm_streaming ns::i; // expected-warning {{ISO C++}} \ + expected-error {{'__arm_streaming' cannot appear here}} \ + expected-error {{'__arm_streaming' only applies to}} +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' only applies to}} + +enum __arm_streaming E1 {}; // expected-error {{'__arm_streaming' only applies to}} +enum __arm_streaming E2; // expected-error {{forbids forward references}} \ + expected-error {{'__arm_streaming' only applies to}} +enum __arm_streaming E1; // expected-error {{'__arm_streaming' only applies to}} +enum __arm_streaming E3 : int; // expected-error {{'__arm_streaming' only applies to}} +enum __arm_streaming { // expected-error {{'__arm_streaming' only applies to}} + k_123 __arm_streaming = 123 // expected-warning {{attributes on an enumerator declaration are a C++17 extension}} \ + expected-error {{'__arm_streaming' only applies to}} +}; +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' only applies to}} + +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' only applies to}} + + __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' only applies to}} + +// 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' only applies to}} + +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}} +} diff --git a/clang/test/Sema/aarch64-sme-attrs-no-sme.c b/clang/test/Sema/aarch64-sme-attrs-no-sme.c --- a/clang/test/Sema/aarch64-sme-attrs-no-sme.c +++ b/clang/test/Sema/aarch64-sme-attrs-no-sme.c @@ -5,32 +5,27 @@ extern int normal_callee(void); -// expected-warning@+1 {{unknown attribute 'arm_streaming' ignored}} -__attribute__((arm_streaming)) -int streaming_caller(void) { +// expected-error@+1 {{'__arm_streaming' is not supported on this target}} +int streaming_caller(void) __arm_streaming { return normal_callee(); } -// expected-warning@+1 {{unknown attribute 'arm_locally_streaming' ignored}} -__attribute__((arm_locally_streaming)) -int locally_streaming_caller(void) { +// expected-error@+1 {{'__arm_locally_streaming' is not supported on this target}} +__arm_locally_streaming int locally_streaming_caller(void) { return normal_callee(); } -// expected-warning@+1 {{unknown attribute 'arm_shared_za' ignored}} -__attribute__((arm_shared_za)) -int shared_za_caller(void) { +// expected-error@+1 {{'__arm_shared_za' is not supported on this target}} +int shared_za_caller(void) __arm_shared_za { return normal_callee(); } -// expected-warning@+1 {{unknown attribute 'arm_preserves_za' ignored}} -__attribute__((arm_preserves_za)) -int preserves_za_caller(void) { +// expected-error@+1 {{'__arm_preserves_za' is not supported on this target}} +int preserves_za_caller(void) __arm_preserves_za { return normal_callee(); } -// expected-warning@+1 {{unknown attribute 'arm_new_za' ignored}} -__attribute__((arm_new_za)) -int new_za_caller(void) { +// expected-error@+1 {{'__arm_new_za' is not supported on this target}} +__arm_new_za int new_za_caller(void) { return normal_callee(); } diff --git a/clang/test/Sema/aarch64-sme-func-attrs.c b/clang/test/Sema/aarch64-sme-func-attrs.c --- a/clang/test/Sema/aarch64-sme-func-attrs.c +++ b/clang/test/Sema/aarch64-sme-func-attrs.c @@ -3,55 +3,55 @@ // Valid attributes -__attribute__((arm_streaming)) void sme_arm_streaming(void); -__attribute__((arm_streaming_compatible)) void sme_arm_streaming_compatible(void); +void sme_arm_streaming(void) __arm_streaming; +void sme_arm_streaming_compatible(void) __arm_streaming_compatible; -__attribute__((arm_new_za)) void sme_arm_new_za(void); -__attribute__((arm_shared_za)) void sme_arm_shared_za(void); -__attribute__((arm_preserves_za)) void sme_arm_preserves_za(void); +void sme_arm_new_za(void) __arm_new_za; +void sme_arm_shared_za(void) __arm_shared_za; +void sme_arm_preserves_za(void) __arm_preserves_za; -__attribute__((arm_streaming, arm_new_za)) void sme_arm_streaming_new_za(void); -__attribute__((arm_streaming, arm_shared_za)) void sme_arm_streaming_shared_za(void); -__attribute__((arm_streaming, arm_preserves_za)) void sme_arm_streaming_preserves_za(void); +void sme_arm_streaming_new_za(void) __arm_streaming __arm_new_za; +void sme_arm_streaming_shared_za(void) __arm_streaming __arm_shared_za; +void sme_arm_streaming_preserves_za(void) __arm_streaming __arm_preserves_za; -__attribute__((arm_streaming_compatible, arm_new_za)) void sme_arm_sc_new_za(void); -__attribute__((arm_streaming_compatible, arm_shared_za)) void sme_arm_sc_shared_za(void); -__attribute__((arm_streaming_compatible, arm_preserves_za)) void sme_arm_sc_preserves_za(void); +void sme_arm_sc_new_za(void) __arm_streaming_compatible __arm_new_za; +void sme_arm_sc_shared_za(void) __arm_streaming_compatible __arm_shared_za; +void sme_arm_sc_preserves_za(void) __arm_streaming_compatible __arm_preserves_za; -__attribute__((arm_shared_za, arm_preserves_za)) void sme_arm_shared_preserves_za(void); +void sme_arm_shared_preserves_za(void) __arm_shared_za __arm_preserves_za; -__attribute__((arm_locally_streaming)) void sme_arm_locally_streaming(void) { } -__attribute__((arm_locally_streaming, arm_streaming)) void sme_arm_streaming_and_locally_streaming(void) { } -__attribute__((arm_locally_streaming, arm_streaming_compatible)) void sme_arm_streaming_and_streaming_compatible(void) { } +__arm_locally_streaming void sme_arm_locally_streaming(void) { } +__arm_locally_streaming void sme_arm_streaming_and_locally_streaming(void) __arm_streaming { } +__arm_locally_streaming void sme_arm_streaming_and_streaming_compatible(void) __arm_streaming_compatible { } -__attribute__((arm_locally_streaming, arm_new_za)) void sme_arm_ls_new_za(void) { } -__attribute__((arm_locally_streaming, arm_shared_za)) void sme_arm_ls_shared_za(void) { } -__attribute__((arm_locally_streaming, arm_preserves_za)) void sme_arm_ls_preserves_za(void) { } +__arm_locally_streaming void sme_arm_ls_new_za(void) __arm_new_za { } +__arm_locally_streaming void sme_arm_ls_shared_za(void) __arm_shared_za { } +__arm_locally_streaming void sme_arm_ls_preserves_za(void) __arm_preserves_za { } // Valid attributes on function pointers -void __attribute__((arm_streaming)) streaming_ptr(void); -typedef __attribute__((arm_streaming)) void (*fptrty1) (void); +void streaming_ptr(void) __arm_streaming; +typedef void (*fptrty1) (void) __arm_streaming; fptrty1 call_streaming_func() { return streaming_ptr; } -void __attribute__((arm_streaming_compatible)) streaming_compatible_ptr(void); -typedef __attribute__((arm_streaming_compatible)) void (*fptrty2) (void); +void streaming_compatible_ptr(void) __arm_streaming_compatible; +typedef void (*fptrty2) (void) __arm_streaming_compatible; fptrty2 call_sc_func() { return streaming_compatible_ptr; } -void __attribute__((arm_new_za)) new_za_ptr(void); -typedef __attribute__((arm_new_za)) void (*fptrty3) (void); +void new_za_ptr(void) __arm_new_za; +typedef void (*fptrty3) (void) __arm_new_za; fptrty3 call_new_za_func() { return new_za_ptr; } -void __attribute__((arm_shared_za)) shared_za_ptr(void); -typedef __attribute__((arm_shared_za)) void (*fptrty4) (void); +void shared_za_ptr(void) __arm_shared_za; +typedef void (*fptrty4) (void) __arm_shared_za; fptrty4 call_shared_za_func() { return shared_za_ptr; } -void __attribute__((arm_preserves_za)) preserves_za_ptr(void); -typedef __attribute__((arm_preserves_za)) void (*fptrty5) (void); +void preserves_za_ptr(void) __arm_preserves_za; +typedef void (*fptrty5) (void) __arm_preserves_za; fptrty5 call_preserve_za_func() { return preserves_za_ptr; } -void __attribute__((arm_shared_za, arm_preserves_za)) shared_preserves_za_ptr(void); -typedef __attribute__((arm_shared_za, arm_preserves_za)) void (*fptrty6) (void); +void shared_preserves_za_ptr(void) __arm_shared_za __arm_preserves_za; +typedef void (*fptrty6) (void) __arm_shared_za __arm_preserves_za; fptrty6 call_shared_preserve_za_func() { return shared_preserves_za_ptr; } typedef void (*fptrty7) (void); @@ -64,184 +64,184 @@ // Invalid attributes -// expected-cpp-error@+4 {{'arm_streaming_compatible' and 'arm_streaming' attributes are not compatible}} +// expected-cpp-error@+4 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_streaming_compatible' and 'arm_streaming' attributes are not compatible}} +// expected-error@+2 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -__attribute__((arm_streaming, arm_streaming_compatible)) void streaming_mode(void); +void streaming_mode(void) __arm_streaming __arm_streaming_compatible; -// expected-cpp-error@+4 {{'arm_streaming' and 'arm_streaming_compatible' attributes are not compatible}} +// expected-cpp-error@+4 {{'__arm_streaming' and '__arm_streaming_compatible' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_streaming' and 'arm_streaming_compatible' attributes are not compatible}} +// expected-error@+2 {{'__arm_streaming' and '__arm_streaming_compatible' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -__attribute__((arm_streaming_compatible, arm_streaming)) void streaming_compatible(void); +void streaming_compatible(void) __arm_streaming_compatible __arm_streaming; -// expected-cpp-error@+4 {{'arm_shared_za' and 'arm_new_za' attributes are not compatible}} +// expected-cpp-error@+4 {{'__arm_shared_za' and '__arm_new_za' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_shared_za' and 'arm_new_za' attributes are not compatible}} +// expected-error@+2 {{'__arm_shared_za' and '__arm_new_za' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -__attribute__((arm_new_za, arm_shared_za)) void new_shared_za(void); +void new_shared_za(void)__arm_new_za __arm_shared_za; -// expected-cpp-error@+4 {{'arm_new_za' and 'arm_shared_za' attributes are not compatible}} +// expected-cpp-error@+4 {{'__arm_new_za' and '__arm_shared_za' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_new_za' and 'arm_shared_za' attributes are not compatible}} +// expected-error@+2 {{'__arm_new_za' and '__arm_shared_za' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -__attribute__((arm_shared_za, arm_new_za)) void shared_new_za(void); +void shared_new_za(void) __arm_shared_za __arm_new_za; -// expected-cpp-error@+4 {{'arm_preserves_za' and 'arm_new_za' attributes are not compatible}} +// expected-cpp-error@+4 {{'__arm_preserves_za' and '__arm_new_za' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_preserves_za' and 'arm_new_za' attributes are not compatible}} +// expected-error@+2 {{'__arm_preserves_za' and '__arm_new_za' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -__attribute__((arm_new_za, arm_preserves_za)) void new_preserves_za(void); +void new_preserves_za(void) __arm_new_za __arm_preserves_za; -// expected-cpp-error@+4 {{'arm_new_za' and 'arm_preserves_za' attributes are not compatible}} +// expected-cpp-error@+4 {{'__arm_new_za' and '__arm_preserves_za' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_new_za' and 'arm_preserves_za' attributes are not compatible}} +// expected-error@+2 {{'__arm_new_za' and '__arm_preserves_za' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -__attribute__((arm_preserves_za, arm_new_za)) void preserves_new_za(void); +void preserves_new_za(void) __arm_preserves_za __arm_new_za; -// Invalid attributes on function pointers +// Invalid attributes on function types -// expected-cpp-error@+4 {{'arm_streaming_compatible' and 'arm_streaming' attributes are not compatible}} +// expected-cpp-error@+4 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_streaming_compatible' and 'arm_streaming' attributes are not compatible}} +// expected-error@+2 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -void __attribute__((arm_streaming, arm_streaming_compatible)) streaming_ptr_invalid(void); -// expected-cpp-error@+4 {{'arm_streaming_compatible' and 'arm_streaming' attributes are not compatible}} +void streaming_ptr_invalid(void) __arm_streaming __arm_streaming_compatible; +// expected-cpp-error@+4 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_streaming_compatible' and 'arm_streaming' attributes are not compatible}} +// expected-error@+2 {{'__arm_streaming_compatible' and '__arm_streaming' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -typedef __attribute__((arm_streaming, arm_streaming_compatible)) void (*fptrty8) (void); +typedef void (*fptrty8) (void) __arm_streaming __arm_streaming_compatible; fptrty8 invalid_streaming_func() { return streaming_ptr_invalid; } -// expected-cpp-error@+4 {{'arm_shared_za' and 'arm_new_za' attributes are not compatible}} +// expected-cpp-error@+4 {{'__arm_shared_za' and '__arm_new_za' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_shared_za' and 'arm_new_za' attributes are not compatible}} +// expected-error@+2 {{'__arm_shared_za' and '__arm_new_za' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -void __attribute__((arm_new_za, arm_shared_za)) shared_za_ptr_invalid(void); -// expected-cpp-error@+4 {{'arm_shared_za' and 'arm_new_za' attributes are not compatible}} +void shared_za_ptr_invalid(void) __arm_new_za __arm_shared_za; +// expected-cpp-error@+4 {{'__arm_shared_za' and '__arm_new_za' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_shared_za' and 'arm_new_za' attributes are not compatible}} +// expected-error@+2 {{'__arm_shared_za' and '__arm_new_za' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -typedef __attribute__((arm_new_za, arm_shared_za)) void (*fptrty9) (void); +typedef void (*fptrty9) (void) __arm_new_za __arm_shared_za; fptrty9 invalid_shared_za_func() { return shared_za_ptr_invalid; } -// expected-cpp-error@+4 {{'arm_preserves_za' and 'arm_new_za' attributes are not compatible}} +// expected-cpp-error@+4 {{'__arm_preserves_za' and '__arm_new_za' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_preserves_za' and 'arm_new_za' attributes are not compatible}} +// expected-error@+2 {{'__arm_preserves_za' and '__arm_new_za' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -void __attribute__((arm_new_za, arm_preserves_za)) preserves_za_ptr_invalid(void); -// expected-cpp-error@+4 {{'arm_preserves_za' and 'arm_new_za' attributes are not compatible}} +void preserves_za_ptr_invalid(void) __arm_new_za __arm_preserves_za; +// expected-cpp-error@+4 {{'__arm_preserves_za' and '__arm_new_za' are not compatible}} // expected-cpp-note@+3 {{conflicting attribute is here}} -// expected-error@+2 {{'arm_preserves_za' and 'arm_new_za' attributes are not compatible}} +// expected-error@+2 {{'__arm_preserves_za' and '__arm_new_za' are not compatible}} // expected-note@+1 {{conflicting attribute is here}} -typedef __attribute__((arm_new_za, arm_preserves_za)) void (*fptrty10) (void); +typedef void (*fptrty10) (void) __arm_new_za __arm_preserves_za; fptrty10 invalid_preserve_za_func() { return preserves_za_ptr_invalid; } -// expected-cpp-error@+2 {{'arm_locally_streaming' attribute only applies to functions}} -// expected-error@+1 {{'arm_locally_streaming' attribute only applies to functions}} -typedef __attribute__((arm_locally_streaming)) void (*fptrty11) (void); +// expected-cpp-error@+2 {{'__arm_locally_streaming' only applies to functions}} +// expected-error@+1 {{'__arm_locally_streaming' only applies to functions}} +typedef void (*fptrty11 __arm_locally_streaming) (void); -// expected-warning@+2 {{'arm_streaming' attribute ignored}} -// expected-warning@+1 {{'arm_streaming' only applies to function types; type here is 'void ()'}} -__attribute__((arm_streaming)) void function_no_prototype(); +// expected-warning@+2 {{'__arm_streaming' attribute ignored}} +// expected-error@+1 {{'__arm_streaming' only applies to function types; type here is 'void ()'}} +void function_no_prototype() __arm_streaming; // // Check for incorrect conversions of function pointers with the attributes // typedef void (*n_ptrty) (void); -typedef __attribute__((arm_streaming)) void (*s_ptrty) (void); +typedef void (*s_ptrty) (void) __arm_streaming; s_ptrty return_valid_streaming_fptr(s_ptrty f) { return f; } -// expected-cpp-error@+2 {{cannot initialize return object of type 's_ptrty' (aka 'void (*)() __attribute__((arm_streaming))') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}} -// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 's_ptrty' (aka 'void (*)(void) __attribute__((arm_streaming))')}} +// expected-cpp-error@+2 {{cannot initialize return object of type 's_ptrty' (aka 'void (*)() __arm_streaming') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}} +// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 's_ptrty' (aka 'void (*)(void) __arm_streaming')}} s_ptrty return_invalid_fptr_streaming_normal(n_ptrty f) { return f; } -// expected-cpp-error@+2 {{cannot initialize return object of type 'n_ptrty' (aka 'void (*)()') with an lvalue of type 's_ptrty' (aka 'void (*)() __attribute__((arm_streaming))')}} -// expected-error@+1 {{incompatible function pointer types returning 's_ptrty' (aka 'void (*)(void) __attribute__((arm_streaming))') from a function with result type 'n_ptrty' (aka 'void (*)(void)')}} +// expected-cpp-error@+2 {{cannot initialize return object of type 'n_ptrty' (aka 'void (*)()') with an lvalue of type 's_ptrty' (aka 'void (*)() __arm_streaming')}} +// expected-error@+1 {{incompatible function pointer types returning 's_ptrty' (aka 'void (*)(void) __arm_streaming') from a function with result type 'n_ptrty' (aka 'void (*)(void)')}} n_ptrty return_invalid_fptr_normal_streaming(s_ptrty f) { return f; } // Test an instance where the result type is not a prototyped function, such that we still get a diagnostic. typedef void (*nonproto_n_ptrty) (); -// expected-cpp-error@+2 {{cannot initialize return object of type 'nonproto_n_ptrty' (aka 'void (*)()') with an lvalue of type 's_ptrty' (aka 'void (*)() __attribute__((arm_streaming))')}} -// expected-error@+1 {{incompatible function pointer types returning 's_ptrty' (aka 'void (*)(void) __attribute__((arm_streaming))') from a function with result type 'nonproto_n_ptrty' (aka 'void (*)()')}} +// expected-cpp-error@+2 {{cannot initialize return object of type 'nonproto_n_ptrty' (aka 'void (*)()') with an lvalue of type 's_ptrty' (aka 'void (*)() __arm_streaming')}} +// expected-error@+1 {{incompatible function pointer types returning 's_ptrty' (aka 'void (*)(void) __arm_streaming') from a function with result type 'nonproto_n_ptrty' (aka 'void (*)()')}} nonproto_n_ptrty return_invalid_fptr_streaming_nonprotonormal(s_ptrty f) { return f; } -typedef __attribute__((arm_streaming_compatible)) void (*sc_ptrty) (void); +typedef void (*sc_ptrty) (void) __arm_streaming_compatible; sc_ptrty return_valid_streaming_compatible_fptr(sc_ptrty f) { return f; } -// expected-cpp-error@+2 {{cannot initialize return object of type 'sc_ptrty' (aka 'void (*)() __attribute__((arm_streaming_compatible))') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}} -// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 'sc_ptrty' (aka 'void (*)(void) __attribute__((arm_streaming_compatible))')}} +// expected-cpp-error@+2 {{cannot initialize return object of type 'sc_ptrty' (aka 'void (*)() __arm_streaming_compatible') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}} +// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 'sc_ptrty' (aka 'void (*)(void) __arm_streaming_compatible')}} sc_ptrty return_invalid_fptr_streaming_compatible_normal(n_ptrty f) { return f; } -// expected-cpp-error@+2 {{cannot initialize return object of type 'n_ptrty' (aka 'void (*)()') with an lvalue of type 'sc_ptrty' (aka 'void (*)() __attribute__((arm_streaming_compatible))')}} -// expected-error@+1 {{incompatible function pointer types returning 'sc_ptrty' (aka 'void (*)(void) __attribute__((arm_streaming_compatible))') from a function with result type 'n_ptrty' (aka 'void (*)(void)')}} +// expected-cpp-error@+2 {{cannot initialize return object of type 'n_ptrty' (aka 'void (*)()') with an lvalue of type 'sc_ptrty' (aka 'void (*)() __arm_streaming_compatible')}} +// expected-error@+1 {{incompatible function pointer types returning 'sc_ptrty' (aka 'void (*)(void) __arm_streaming_compatible') from a function with result type 'n_ptrty' (aka 'void (*)(void)')}} n_ptrty return_invalid_fptr_normal_streaming_compatible(sc_ptrty f) { return f; } -typedef __attribute__((arm_new_za)) void (*nz_ptrty) (void); +typedef void (*nz_ptrty) (void) __arm_new_za; nz_ptrty return_valid_new_za_fptr(nz_ptrty f) { return f; } -// expected-cpp-error@+2 {{cannot initialize return object of type 'nz_ptrty' (aka 'void (*)() __attribute__((arm_new_za))') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}} -// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 'nz_ptrty' (aka 'void (*)(void) __attribute__((arm_new_za))')}} +// expected-cpp-error@+2 {{cannot initialize return object of type 'nz_ptrty' (aka 'void (*)() __arm_new_za') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}} +// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 'nz_ptrty' (aka 'void (*)(void) __arm_new_za')}} nz_ptrty return_invalid_fptr_new_za_normal(n_ptrty f) { return f; } -// expected-cpp-error@+2 {{cannot initialize return object of type 'n_ptrty' (aka 'void (*)()') with an lvalue of type 'nz_ptrty' (aka 'void (*)() __attribute__((arm_new_za))')}} -// expected-error@+1 {{incompatible function pointer types returning 'nz_ptrty' (aka 'void (*)(void) __attribute__((arm_new_za))') from a function with result type 'n_ptrty' (aka 'void (*)(void)')}} +// expected-cpp-error@+2 {{cannot initialize return object of type 'n_ptrty' (aka 'void (*)()') with an lvalue of type 'nz_ptrty' (aka 'void (*)() __arm_new_za')}} +// expected-error@+1 {{incompatible function pointer types returning 'nz_ptrty' (aka 'void (*)(void) __arm_new_za') from a function with result type 'n_ptrty' (aka 'void (*)(void)')}} n_ptrty return_invalid_fptr_normal_new_za(nz_ptrty f) { return f; } -typedef __attribute__((arm_shared_za)) void (*sz_ptrty) (void); +typedef void (*sz_ptrty) (void) __arm_shared_za; sz_ptrty return_valid_shared_za_fptr(sz_ptrty f) { return f; } -// expected-cpp-error@+2 {{cannot initialize return object of type 'sz_ptrty' (aka 'void (*)() __attribute__((arm_shared_za))') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}} -// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 'sz_ptrty' (aka 'void (*)(void) __attribute__((arm_shared_za))')}} +// expected-cpp-error@+2 {{cannot initialize return object of type 'sz_ptrty' (aka 'void (*)() __arm_shared_za') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}} +// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 'sz_ptrty' (aka 'void (*)(void) __arm_shared_za')}} sz_ptrty return_invalid_fptr_shared_za_normal(n_ptrty f) { return f; } -// expected-cpp-error@+2 {{cannot initialize return object of type 'n_ptrty' (aka 'void (*)()') with an lvalue of type 'sz_ptrty' (aka 'void (*)() __attribute__((arm_shared_za))')}} -// expected-error@+1 {{incompatible function pointer types returning 'sz_ptrty' (aka 'void (*)(void) __attribute__((arm_shared_za))') from a function with result type 'n_ptrty' (aka 'void (*)(void)')}} +// expected-cpp-error@+2 {{cannot initialize return object of type 'n_ptrty' (aka 'void (*)()') with an lvalue of type 'sz_ptrty' (aka 'void (*)() __arm_shared_za')}} +// expected-error@+1 {{incompatible function pointer types returning 'sz_ptrty' (aka 'void (*)(void) __arm_shared_za') from a function with result type 'n_ptrty' (aka 'void (*)(void)')}} n_ptrty return_invalid_fptr_normal_shared_za(sz_ptrty f) { return f; } -typedef __attribute__((arm_preserves_za)) void (*pz_ptrty) (void); +typedef void (*pz_ptrty) (void) __arm_preserves_za; pz_ptrty return_valid_preserves_za_fptr(pz_ptrty f) { return f; } -// expected-cpp-error@+2 {{cannot initialize return object of type 'pz_ptrty' (aka 'void (*)() __attribute__((arm_preserves_za))') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}} -// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 'pz_ptrty' (aka 'void (*)(void) __attribute__((arm_preserves_za))')}} +// expected-cpp-error@+2 {{cannot initialize return object of type 'pz_ptrty' (aka 'void (*)() __arm_preserves_za') with an lvalue of type 'n_ptrty' (aka 'void (*)()')}} +// expected-error@+1 {{incompatible function pointer types returning 'n_ptrty' (aka 'void (*)(void)') from a function with result type 'pz_ptrty' (aka 'void (*)(void) __arm_preserves_za')}} pz_ptrty return_invalid_fptr_preserves_za_normal(n_ptrty f) { return f; } // No diagnostics, the preserves_za hint should be dropped silently. n_ptrty return_invalid_fptr_normal_preserves_za(pz_ptrty f) { return f; } // Test template instantiations #ifdef __cplusplus -template __attribute__((arm_streaming)) T templated(T x) { return x; } -template <> __attribute__((arm_streaming)) int templated(int x) { return x + 1; } -template <> __attribute__((arm_streaming)) float templated(float x) { return x + 2; } +template T templated(T x) __arm_streaming { return x; } +template <> int templated(int x) __arm_streaming { return x + 1; } +template <> float templated(float x) __arm_streaming { return x + 2; } // expected-cpp-error@+2 {{explicit instantiation of 'templated' does not refer to a function template, variable template, member function, member class, or static data member}} -// expected-cpp-note@-4 {{candidate template ignored: could not match 'short (short) __attribute__((arm_streaming))' against 'short (short)'}} +// expected-cpp-note@-4 {{candidate template ignored: could not match 'short (short) __arm_streaming' against 'short (short)'}} template short templated(short); #endif // Conflicting attributes on redeclarations -// expected-error@+5 {{function declared ''void (void) __attribute__((arm_streaming_compatible))'' was previously declared ''void (void) __attribute__((arm_streaming))'' with different SME function attributes}} +// expected-error@+5 {{function declared ''void (void) __arm_streaming_compatible'' was previously declared ''void (void) __arm_streaming'' with different SME function attributes}} // expected-note@+3 {{previous declaration is here}} -// expected-cpp-error@+3 {{function declared ''void () __attribute__((arm_streaming_compatible))'' was previously declared ''void () __attribute__((arm_streaming))'' with different SME function attributes}} +// expected-cpp-error@+3 {{function declared ''void () __arm_streaming_compatible'' was previously declared ''void () __arm_streaming'' with different SME function attributes}} // expected-cpp-note@+1 {{previous declaration is here}} -__attribute__((arm_streaming)) void redecl(void); -__attribute__((arm_streaming_compatible)) void redecl(void) { } +void redecl(void) __arm_streaming; +void redecl(void) __arm_streaming_compatible { } -// expected-error@+5 {{function declared ''void (void) __attribute__((arm_shared_za))'' was previously declared ''void (void) __attribute__((arm_shared_za)) __attribute__((arm_preserves_za))'' with different SME function attributes}} +// expected-error@+5 {{function declared ''void (void) __arm_shared_za'' was previously declared ''void (void) __arm_shared_za __arm_preserves_za'' with different SME function attributes}} // expected-note@+3 {{previous declaration is here}} -// expected-cpp-error@+3 {{function declared ''void () __attribute__((arm_shared_za))'' was previously declared ''void () __attribute__((arm_shared_za)) __attribute__((arm_preserves_za))'' with different SME function attributes}} +// expected-cpp-error@+3 {{function declared ''void () __arm_shared_za'' was previously declared ''void () __arm_shared_za __arm_preserves_za'' with different SME function attributes}} // expected-cpp-note@+1 {{previous declaration is here}} -__attribute__((arm_shared_za, arm_preserves_za)) void redecl_nopreserve_za(void); -__attribute__((arm_shared_za)) void redecl_nopreserve_za(void) { } +void redecl_nopreserve_za(void) __arm_shared_za __arm_preserves_za; +void redecl_nopreserve_za(void) __arm_shared_za { } #ifdef __cplusplus struct S { - virtual __attribute__((arm_shared_za)) void shared_za_memberfn(void); + virtual void shared_za_memberfn(void) __arm_shared_za; }; struct S2 : public S { -// expected-cpp-error@+2 {{virtual function 'shared_za_memberfn' has different attributes ('void () __attribute__((arm_new_za))') than the function it overrides (which has 'void () __attribute__((arm_shared_za))')}} +// expected-cpp-error@+2 {{virtual function 'shared_za_memberfn' has different attributes ('void () __arm_new_za') than the function it overrides (which has 'void () __arm_shared_za')}} // expected-cpp-note@-5 {{overridden virtual function is here}} - __attribute__((arm_new_za)) void shared_za_memberfn(void) override; + void shared_za_memberfn(void) __arm_new_za override; }; // Check that the attribute propagates through template instantiations. @@ -256,23 +256,17 @@ }; template <> -struct S3 { +struct S3 { static constexpr int value = 2; }; void normal_func() {} -void streaming_func() __attribute__((arm_streaming)) {} +void streaming_func() __arm_streaming {} static_assert(S3::value == 1, "why are we picking the wrong specialization?"); static_assert(S3::value == 2, "why are we picking the wrong specialization?"); #endif -// expected-cpp-error@+2 {{'arm_streaming' attribute takes no arguments}} -// expected-error@+1 {{'arm_streaming' attribute takes no arguments}} -__attribute__((arm_streaming(0))) void invalid_streaming_args(void); - -// expected-cpp-error@+4 {{attribute only applies to non-K&R-style functions}} -// expected-cpp-warning@+3 {{'arm_streaming' only applies to function types; type here is 'int'}} -// expected-error@+2 {{attribute only applies to non-K&R-style functions}} -// expected-warning@+1 {{'arm_streaming' only applies to function types; type here is 'int'}} -__attribute__((arm_streaming)) int invalid_type_for_attribute; +// expected-cpp-error@+2 {{'__arm_streaming' only applies to function types; type here is 'int'}} +// expected-error@+1 {{'__arm_streaming' only applies to function types; type here is 'int'}} +int invalid_type_for_attribute __arm_streaming; 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 @@ -3420,6 +3420,7 @@ fn("C2x", C2x); OS << "case AttributeCommonInfo::Syntax::AS_Keyword:\n"; OS << "case AttributeCommonInfo::Syntax::AS_ContextSensitiveKeyword:\n"; + OS << "case AttributeCommonInfo::Syntax::AS_AttributeLikeKeyword:\n"; OS << " llvm_unreachable(\"hasAttribute not supported for keyword\");\n"; OS << " return 0;\n"; @@ -3793,7 +3794,7 @@ 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.isAttributeLikeKeyword() << D->getLocation();\n"; OS << " return false;\n"; OS << "}\n\n"; } @@ -3822,7 +3823,7 @@ OS << (Warn ? "warn_attribute_wrong_decl_type_str" : "err_attribute_wrong_decl_type_str"); OS << ")\n"; - OS << " << Attr << "; + OS << " << Attr << Attr.isAttributeLikeKeyword() << "; OS << CalculateDiagnostic(*SubjectObj) << ";\n"; OS << " return false;\n"; OS << " }\n"; @@ -3837,7 +3838,7 @@ 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.isAttributeLikeKeyword() << St->getBeginLoc();\n"; OS << " return false;\n"; OS << "}\n\n"; } @@ -3856,7 +3857,7 @@ OS << (Warn ? "warn_attribute_wrong_decl_type_str" : "err_attribute_wrong_decl_type_str"); OS << ")\n"; - OS << " << Attr << "; + OS << " << Attr << Attr.isAttributeLikeKeyword() << "; OS << CalculateDiagnostic(*SubjectObj) << ";\n"; OS << " return false;\n"; OS << " }\n"; @@ -3927,7 +3928,8 @@ 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.isAttributeLikeKeyword() ||" + << " A->isAttributeLikeKeyword());\n"; OS << " S.Diag(A->getLocation(), diag::note_conflicting_attribute);"; OS << " \nreturn false;\n"; OS << " }\n"; @@ -3948,7 +3950,8 @@ << ">()) {\n"; MergeDeclOS << " S.Diag(First->getLocation(), " << "diag::err_attributes_are_not_compatible) << First << " - << "Second;\n"; + << "Second << (First->isAttributeLikeKeyword() || " + << "Second->isAttributeLikeKeyword());\n"; MergeDeclOS << " S.Diag(Second->getLocation(), " << "diag::note_conflicting_attribute);\n"; MergeDeclOS << " return false;\n"; @@ -3988,7 +3991,8 @@ MergeStmtOS << " if (Iter != C.end()) {\n"; MergeStmtOS << " S.Diag((*Iter)->getLocation(), " << "diag::err_attributes_are_not_compatible) << *Iter << " - << "Second;\n"; + << "Second << ((*Iter)->isAttributeLikeKeyword() || " + << "Second->isAttributeLikeKeyword());\n"; MergeStmtOS << " S.Diag(Second->getLocation(), " << "diag::note_conflicting_attribute);\n"; MergeStmtOS << " return false;\n"; @@ -4436,7 +4440,8 @@ OS << " } else if (AttributeCommonInfo::AS_C2x == Syntax) {\n"; StringMatcher("Name", C2x, OS).Emit(); OS << " } else if (AttributeCommonInfo::AS_Keyword == Syntax || "; - OS << "AttributeCommonInfo::AS_ContextSensitiveKeyword == Syntax) {\n"; + OS << "AttributeCommonInfo::AS_ContextSensitiveKeyword == Syntax || "; + OS << "AttributeCommonInfo::AS_AttributeLikeKeyword == Syntax) {\n"; StringMatcher("Name", Keywords, OS).Emit(); OS << " } else if (AttributeCommonInfo::AS_Pragma == Syntax) {\n"; StringMatcher("Name", Pragma, OS).Emit();