139 changes: 82 additions & 57 deletions clang/include/clang/Basic/Attr.td
Original file line number Diff line number Diff line change
Expand Up @@ -311,7 +311,20 @@ class C2x<string namespace, string name, int version = 1>
string Namespace = namespace;
}

class Keyword<string name> : Spelling<name, "Keyword">;
class Keyword<string name, bit hasOwnParseRules>
: Spelling<name, "Keyword"> {
bit HasOwnParseRules = hasOwnParseRules;
}

// A keyword that can appear wherever a standard attribute can appear,
// and that appertains to whatever a standard attribute would appertain to.
// This is useful for things that affect semantics but that should otherwise
// be treated like standard attributes.
class RegularKeyword<string name> : Keyword<name, 0> {}

// A keyword that has its own individual parsing rules.
class CustomKeyword<string name> : Keyword<name, 1> {}

class Pragma<string namespace, string name> : Spelling<name, "Pragma"> {
string Namespace = namespace;
}
Expand Down Expand Up @@ -709,13 +722,13 @@ def ArmBuiltinAlias : InheritableAttr, TargetSpecificAttr<TargetAnyArm> {
}

def Aligned : InheritableAttr {
let Spellings = [GCC<"aligned">, Declspec<"align">, Keyword<"alignas">,
Keyword<"_Alignas">];
let Spellings = [GCC<"aligned">, Declspec<"align">, CustomKeyword<"alignas">,
CustomKeyword<"_Alignas">];
let Args = [AlignedArgument<"Alignment", 1>];
let Accessors = [Accessor<"isGNU", [GCC<"aligned">]>,
Accessor<"isC11", [Keyword<"_Alignas">]>,
Accessor<"isAlignas", [Keyword<"alignas">,
Keyword<"_Alignas">]>,
Accessor<"isC11", [CustomKeyword<"_Alignas">]>,
Accessor<"isAlignas", [CustomKeyword<"alignas">,
CustomKeyword<"_Alignas">]>,
Accessor<"isDeclspec",[Declspec<"align">]>];
let Documentation = [Undocumented];
}
Expand Down Expand Up @@ -756,7 +769,7 @@ def AlignNatural : InheritableAttr {

def AlwaysInline : DeclOrStmtAttr {
let Spellings = [GCC<"always_inline">, CXX11<"clang", "always_inline">,
C2x<"clang", "always_inline">, Keyword<"__forceinline">];
C2x<"clang", "always_inline">, CustomKeyword<"__forceinline">];
let Accessors = [Accessor<"isClangAlwaysInline", [CXX11<"clang", "always_inline">,
C2x<"clang", "always_inline">]>];
let Subjects = SubjectList<[Function, Stmt], WarnDiag,
Expand Down Expand Up @@ -879,7 +892,7 @@ def AVRSignal : InheritableAttr, TargetSpecificAttr<TargetAVR> {
}

def AsmLabel : InheritableAttr {
let Spellings = [Keyword<"asm">, Keyword<"__asm__">];
let Spellings = [CustomKeyword<"asm">, CustomKeyword<"__asm__">];
let Args = [
// Label specifies the mangled name for the decl.
StringArgument<"Label">,
Expand Down Expand Up @@ -997,7 +1010,7 @@ def CarriesDependency : InheritableParamAttr {
}

def CDecl : DeclOrTypeAttr {
let Spellings = [GCC<"cdecl">, Keyword<"__cdecl">, Keyword<"_cdecl">];
let Spellings = [GCC<"cdecl">, CustomKeyword<"__cdecl">, CustomKeyword<"_cdecl">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [Undocumented];
}
Expand Down Expand Up @@ -1122,10 +1135,10 @@ def Const : InheritableAttr {
def ConstInit : InheritableAttr {
// This attribute does not have a C [[]] spelling because it requires the
// CPlusPlus language option.
let Spellings = [Keyword<"constinit">,
let Spellings = [CustomKeyword<"constinit">,
Clang<"require_constant_initialization", 0>];
let Subjects = SubjectList<[GlobalVar], ErrorDiag>;
let Accessors = [Accessor<"isConstinit", [Keyword<"constinit">]>];
let Accessors = [Accessor<"isConstinit", [CustomKeyword<"constinit">]>];
let Documentation = [ConstInitDocs];
let LangOpts = [CPlusPlus];
let SimpleHandler = 1;
Expand Down Expand Up @@ -1276,7 +1289,7 @@ def SYCLSpecialClass: InheritableAttr {
}

def C11NoReturn : InheritableAttr {
let Spellings = [Keyword<"_Noreturn">];
let Spellings = [CustomKeyword<"_Noreturn">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let SemaHandler = 0;
let Documentation = [C11NoReturnDocs];
Expand All @@ -1292,7 +1305,7 @@ def CXX11NoReturn : InheritableAttr {
// Similar to CUDA, OpenCL attributes do not receive a [[]] spelling because
// the specification does not expose them with one currently.
def OpenCLKernel : InheritableAttr {
let Spellings = [Keyword<"__kernel">, Keyword<"kernel">];
let Spellings = [CustomKeyword<"__kernel">, CustomKeyword<"kernel">];
let Subjects = SubjectList<[Function], ErrorDiag>;
let Documentation = [Undocumented];
let SimpleHandler = 1;
Expand All @@ -1316,26 +1329,28 @@ def OpenCLIntelReqdSubGroupSize: InheritableAttr {
// This attribute is both a type attribute, and a declaration attribute (for
// parameter variables).
def OpenCLAccess : Attr {
let Spellings = [Keyword<"__read_only">, Keyword<"read_only">,
Keyword<"__write_only">, Keyword<"write_only">,
Keyword<"__read_write">, Keyword<"read_write">];
let Spellings = [CustomKeyword<"__read_only">, CustomKeyword<"read_only">,
CustomKeyword<"__write_only">, CustomKeyword<"write_only">,
CustomKeyword<"__read_write">, CustomKeyword<"read_write">];
let Subjects = SubjectList<[ParmVar, TypedefName], ErrorDiag>;
let Accessors = [Accessor<"isReadOnly", [Keyword<"__read_only">,
Keyword<"read_only">]>,
Accessor<"isReadWrite", [Keyword<"__read_write">,
Keyword<"read_write">]>,
Accessor<"isWriteOnly", [Keyword<"__write_only">,
Keyword<"write_only">]>];
let Accessors = [Accessor<"isReadOnly", [CustomKeyword<"__read_only">,
CustomKeyword<"read_only">]>,
Accessor<"isReadWrite", [CustomKeyword<"__read_write">,
CustomKeyword<"read_write">]>,
Accessor<"isWriteOnly", [CustomKeyword<"__write_only">,
CustomKeyword<"write_only">]>];
let Documentation = [OpenCLAccessDocs];
}

def OpenCLPrivateAddressSpace : TypeAttr {
let Spellings = [Keyword<"__private">, Keyword<"private">, Clang<"opencl_private">];
let Spellings = [CustomKeyword<"__private">, CustomKeyword<"private">,
Clang<"opencl_private">];
let Documentation = [OpenCLAddressSpacePrivateDocs];
}

def OpenCLGlobalAddressSpace : TypeAttr {
let Spellings = [Keyword<"__global">, Keyword<"global">, Clang<"opencl_global">];
let Spellings = [CustomKeyword<"__global">, CustomKeyword<"global">,
Clang<"opencl_global">];
let Documentation = [OpenCLAddressSpaceGlobalDocs];
}

Expand All @@ -1350,17 +1365,20 @@ def OpenCLGlobalHostAddressSpace : TypeAttr {
}

def OpenCLLocalAddressSpace : TypeAttr {
let Spellings = [Keyword<"__local">, Keyword<"local">, Clang<"opencl_local">];
let Spellings = [CustomKeyword<"__local">, CustomKeyword<"local">,
Clang<"opencl_local">];
let Documentation = [OpenCLAddressSpaceLocalDocs];
}

def OpenCLConstantAddressSpace : TypeAttr {
let Spellings = [Keyword<"__constant">, Keyword<"constant">, Clang<"opencl_constant">];
let Spellings = [CustomKeyword<"__constant">, CustomKeyword<"constant">,
Clang<"opencl_constant">];
let Documentation = [OpenCLAddressSpaceConstantDocs];
}

def OpenCLGenericAddressSpace : TypeAttr {
let Spellings = [Keyword<"__generic">, Keyword<"generic">, Clang<"opencl_generic">];
let Spellings = [CustomKeyword<"__generic">, CustomKeyword<"generic">,
Clang<"opencl_generic">];
let Documentation = [OpenCLAddressSpaceGenericDocs];
}

Expand Down Expand Up @@ -1476,20 +1494,20 @@ def MustTail : StmtAttr {
}

def FastCall : DeclOrTypeAttr {
let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">,
Keyword<"_fastcall">];
let Spellings = [GCC<"fastcall">, CustomKeyword<"__fastcall">,
CustomKeyword<"_fastcall">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [FastCallDocs];
}

def RegCall : DeclOrTypeAttr {
let Spellings = [GCC<"regcall">, Keyword<"__regcall">];
let Spellings = [GCC<"regcall">, CustomKeyword<"__regcall">];
let Documentation = [RegCallDocs];
}

def Final : InheritableAttr {
let Spellings = [Keyword<"final">, Keyword<"sealed">];
let Accessors = [Accessor<"isSpelledAsSealed", [Keyword<"sealed">]>];
let Spellings = [CustomKeyword<"final">, CustomKeyword<"sealed">];
let Accessors = [Accessor<"isSpelledAsSealed", [CustomKeyword<"sealed">]>];
let SemaHandler = 0;
// Omitted from docs, since this is language syntax, not an attribute, as far
// as users are concerned.
Expand Down Expand Up @@ -1835,7 +1853,7 @@ def Convergent : InheritableAttr {
}

def NoInline : DeclOrStmtAttr {
let Spellings = [Keyword<"__noinline__">, GCC<"noinline">,
let Spellings = [CustomKeyword<"__noinline__">, GCC<"noinline">,
CXX11<"clang", "noinline">, C2x<"clang", "noinline">,
Declspec<"noinline">];
let Accessors = [Accessor<"isClangNoInline", [CXX11<"clang", "noinline">,
Expand Down Expand Up @@ -2031,35 +2049,35 @@ def PassObjectSize : InheritableParamAttr {

// Nullability type attributes.
def TypeNonNull : TypeAttr {
let Spellings = [Keyword<"_Nonnull">];
let Spellings = [CustomKeyword<"_Nonnull">];
let Documentation = [TypeNonNullDocs];
}

def TypeNullable : TypeAttr {
let Spellings = [Keyword<"_Nullable">];
let Spellings = [CustomKeyword<"_Nullable">];
let Documentation = [TypeNullableDocs];
}

def TypeNullableResult : TypeAttr {
let Spellings = [Keyword<"_Nullable_result">];
let Spellings = [CustomKeyword<"_Nullable_result">];
let Documentation = [TypeNullableResultDocs];
}

def TypeNullUnspecified : TypeAttr {
let Spellings = [Keyword<"_Null_unspecified">];
let Spellings = [CustomKeyword<"_Null_unspecified">];
let Documentation = [TypeNullUnspecifiedDocs];
}

// This is a marker used to indicate that an __unsafe_unretained qualifier was
// ignored because ARC is not enabled. The usual representation for this
// qualifier is as an ObjCOwnership attribute with Kind == "none".
def ObjCInertUnsafeUnretained : TypeAttr {
let Spellings = [Keyword<"__unsafe_unretained">];
let Spellings = [CustomKeyword<"__unsafe_unretained">];
let Documentation = [InternalOnly];
}

def ObjCKindOf : TypeAttr {
let Spellings = [Keyword<"__kindof">];
let Spellings = [CustomKeyword<"__kindof">];
let Documentation = [Undocumented];
}

Expand Down Expand Up @@ -2358,7 +2376,7 @@ def Overloadable : Attr {
}

def Override : InheritableAttr {
let Spellings = [Keyword<"override">];
let Spellings = [CustomKeyword<"override">];
let SemaHandler = 0;
// Omitted from docs, since this is language syntax, not an attribute, as far
// as users are concerned.
Expand Down Expand Up @@ -2416,6 +2434,11 @@ def AArch64SVEPcs: DeclOrTypeAttr {
let Documentation = [AArch64SVEPcsDocs];
}

def ArmStreaming : TypeAttr, TargetSpecificAttr<TargetAArch64> {
let Spellings = [RegularKeyword<"__arm_streaming">];
let Documentation = [ArmStreamingDocs];
}

def Pure : InheritableAttr {
let Spellings = [GCC<"pure">];
let Documentation = [Undocumented];
Expand Down Expand Up @@ -2603,7 +2626,8 @@ def Sentinel : InheritableAttr {
}

def StdCall : DeclOrTypeAttr {
let Spellings = [GCC<"stdcall">, Keyword<"__stdcall">, Keyword<"_stdcall">];
let Spellings = [GCC<"stdcall">, CustomKeyword<"__stdcall">,
CustomKeyword<"_stdcall">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [StdCallDocs];
}
Expand Down Expand Up @@ -2672,15 +2696,15 @@ def SysVABI : DeclOrTypeAttr {
}

def ThisCall : DeclOrTypeAttr {
let Spellings = [GCC<"thiscall">, Keyword<"__thiscall">,
Keyword<"_thiscall">];
let Spellings = [GCC<"thiscall">, CustomKeyword<"__thiscall">,
CustomKeyword<"_thiscall">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [ThisCallDocs];
}

def VectorCall : DeclOrTypeAttr {
let Spellings = [Clang<"vectorcall">, Keyword<"__vectorcall">,
Keyword<"_vectorcall">];
let Spellings = [Clang<"vectorcall">, CustomKeyword<"__vectorcall">,
CustomKeyword<"_vectorcall">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [VectorCallDocs];
}
Expand All @@ -2699,7 +2723,8 @@ def ZeroCallUsedRegs : InheritableAttr {
}

def Pascal : DeclOrTypeAttr {
let Spellings = [Clang<"pascal">, Keyword<"__pascal">, Keyword<"_pascal">];
let Spellings = [Clang<"pascal">, CustomKeyword<"__pascal">,
CustomKeyword<"_pascal">];
// let Subjects = [Function, ObjCMethod];
let Documentation = [Undocumented];
}
Expand Down Expand Up @@ -3596,37 +3621,37 @@ def Thread : Attr {
}

def Win64 : IgnoredAttr {
let Spellings = [Keyword<"__w64">];
let Spellings = [CustomKeyword<"__w64">];
let LangOpts = [MicrosoftExt];
}

def Ptr32 : TypeAttr {
let Spellings = [Keyword<"__ptr32">];
let Spellings = [CustomKeyword<"__ptr32">];
let Documentation = [Ptr32Docs];
}

def Ptr64 : TypeAttr {
let Spellings = [Keyword<"__ptr64">];
let Spellings = [CustomKeyword<"__ptr64">];
let Documentation = [Ptr64Docs];
}

def SPtr : TypeAttr {
let Spellings = [Keyword<"__sptr">];
let Spellings = [CustomKeyword<"__sptr">];
let Documentation = [SPtrDocs];
}

def UPtr : TypeAttr {
let Spellings = [Keyword<"__uptr">];
let Spellings = [CustomKeyword<"__uptr">];
let Documentation = [UPtrDocs];
}

def MSInheritance : InheritableAttr {
let LangOpts = [MicrosoftExt];
let Args = [DefaultBoolArgument<"BestCase", /*default*/1, /*fake*/1>];
let Spellings = [Keyword<"__single_inheritance">,
Keyword<"__multiple_inheritance">,
Keyword<"__virtual_inheritance">,
Keyword<"__unspecified_inheritance">];
let Spellings = [CustomKeyword<"__single_inheritance">,
CustomKeyword<"__multiple_inheritance">,
CustomKeyword<"__virtual_inheritance">,
CustomKeyword<"__unspecified_inheritance">];
let AdditionalMembers = [{
MSInheritanceModel getInheritanceModel() const {
// The spelling enum should agree with MSInheritanceModel.
Expand Down Expand Up @@ -4126,7 +4151,7 @@ def HLSLResource : InheritableAttr {
}

def HLSLGroupSharedAddressSpace : TypeAttr {
let Spellings = [Keyword<"groupshared">];
let Spellings = [CustomKeyword<"groupshared">];
let Subjects = SubjectList<[Var]>;
let Documentation = [HLSLGroupSharedAddressSpaceDocs];
}
Expand Down Expand Up @@ -4158,7 +4183,7 @@ def FunctionReturnThunks : InheritableAttr,
}

def WebAssemblyFuncref : TypeAttr, TargetSpecificAttr<TargetWebAssembly> {
let Spellings = [Keyword<"__funcref">];
let Spellings = [CustomKeyword<"__funcref">];
let Documentation = [WebAssemblyExportNameDocs];
let Subjects = SubjectList<[FunctionPointer], ErrorDiag>;
}
Expand Down
35 changes: 35 additions & 0 deletions clang/include/clang/Basic/AttrDocs.td
Original file line number Diff line number Diff line change
Expand Up @@ -6551,6 +6551,41 @@ Requirements on Development Tools - Engineering Specification Documentation
}];
}

def ArmStreamingDocs : Documentation {
let Category = DocCatType;
let Content = [{
.. Note:: This attribute has not been implemented yet, but once it is
implemented, it will behave as described below.

The ``__arm_streaming`` keyword is only available on AArch64 targets.
It applies to function types and specifies that the function has a
“streaming interface”. This means that:

* the function requires the Scalable Matrix Extension (SME)

* the function must be entered in streaming mode (that is, with PSTATE.SM
set to 1)

* the function must return in streaming mode

See `Procedure Call Standard for the Arm® 64-bit Architecture (AArch64)
<https://github.com/ARM-software/abi-aa>`_ for more details about
streaming-interface functions.

Clang manages PSTATE.SM automatically; it is not the source code's
responsibility to do this. For example, if a normal non-streaming
function calls an ``__arm_streaming`` function, Clang generates code
that switches into streaming mode before calling the function and
switches back to non-streaming mode on return.

``__arm_streaming`` can appear anywhere that a standard ``[[…]]`` type
attribute can appear.

See `Arm C Language Extensions <https://github.com/ARM-software/acle>`_
for more details about this extension, and for other related SME features.
}];
}

def AlwaysInlineDocs : Documentation {
let Category = DocCatFunction;
let Content = [{
Expand Down
29 changes: 21 additions & 8 deletions clang/include/clang/Basic/AttributeCommonInfo.h
Original file line number Diff line number Diff line change
Expand Up @@ -77,6 +77,7 @@ class AttributeCommonInfo {
unsigned SyntaxUsed : 4;
unsigned SpellingIndex : 4;
unsigned IsAlignas : 1;
unsigned IsRegularKeywordAttribute : 1;

protected:
static constexpr unsigned SpellingNotCalculated = 0xf;
Expand All @@ -86,24 +87,29 @@ class AttributeCommonInfo {
/// including its syntax and spelling.
class Form {
public:
constexpr Form(Syntax SyntaxUsed, unsigned SpellingIndex, bool IsAlignas)
constexpr Form(Syntax SyntaxUsed, unsigned SpellingIndex, bool IsAlignas,
bool IsRegularKeywordAttribute)
: SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingIndex),
IsAlignas(IsAlignas) {}
IsAlignas(IsAlignas),
IsRegularKeywordAttribute(IsRegularKeywordAttribute) {}
constexpr Form(tok::TokenKind Tok)
: SyntaxUsed(AS_Keyword), SpellingIndex(SpellingNotCalculated),
IsAlignas(Tok == tok::kw_alignas) {}
IsAlignas(Tok == tok::kw_alignas),
IsRegularKeywordAttribute(tok::isRegularKeywordAttribute(Tok)) {}

Syntax getSyntax() const { return Syntax(SyntaxUsed); }
unsigned getSpellingIndex() const { return SpellingIndex; }
bool isAlignas() const { return IsAlignas; }
bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; }

static Form GNU() { return AS_GNU; }
static Form CXX11() { return AS_CXX11; }
static Form C2x() { return AS_C2x; }
static Form Declspec() { return AS_Declspec; }
static Form Microsoft() { return AS_Microsoft; }
static Form Keyword(bool IsAlignas) {
return Form(AS_Keyword, SpellingNotCalculated, IsAlignas);
static Form Keyword(bool IsAlignas, bool IsRegularKeywordAttribute) {
return Form(AS_Keyword, SpellingNotCalculated, IsAlignas,
IsRegularKeywordAttribute);
}
static Form Pragma() { return AS_Pragma; }
static Form ContextSensitiveKeyword() { return AS_ContextSensitiveKeyword; }
Expand All @@ -113,11 +119,12 @@ class AttributeCommonInfo {
private:
constexpr Form(Syntax SyntaxUsed)
: SyntaxUsed(SyntaxUsed), SpellingIndex(SpellingNotCalculated),
IsAlignas(0) {}
IsAlignas(0), IsRegularKeywordAttribute(0) {}

unsigned SyntaxUsed : 4;
unsigned SpellingIndex : 4;
unsigned IsAlignas : 1;
unsigned IsRegularKeywordAttribute : 1;
};

AttributeCommonInfo(const IdentifierInfo *AttrName,
Expand All @@ -127,7 +134,8 @@ class AttributeCommonInfo {
ScopeLoc(ScopeLoc), AttrKind(AttrKind),
SyntaxUsed(FormUsed.getSyntax()),
SpellingIndex(FormUsed.getSpellingIndex()),
IsAlignas(FormUsed.isAlignas()) {
IsAlignas(FormUsed.isAlignas()),
IsRegularKeywordAttribute(FormUsed.isRegularKeywordAttribute()) {
assert(SyntaxUsed >= AS_GNU && SyntaxUsed <= AS_Implicit &&
"Invalid syntax!");
}
Expand All @@ -154,7 +162,10 @@ class AttributeCommonInfo {

Kind getParsedKind() const { return Kind(AttrKind); }
Syntax getSyntax() const { return Syntax(SyntaxUsed); }
Form getForm() const { return Form(getSyntax(), SpellingIndex, IsAlignas); }
Form getForm() const {
return Form(getSyntax(), SpellingIndex, IsAlignas,
IsRegularKeywordAttribute);
}
const IdentifierInfo *getAttrName() const { return AttrName; }
SourceLocation getLoc() const { return AttrRange.getBegin(); }
SourceRange getRange() const { return AttrRange; }
Expand Down Expand Up @@ -191,6 +202,8 @@ class AttributeCommonInfo {
return SyntaxUsed == AS_Keyword || SyntaxUsed == AS_ContextSensitiveKeyword;
}

bool isRegularKeywordAttribute() const { return IsRegularKeywordAttribute; }

bool isContextSensitiveKeywordAttribute() const {
return SyntaxUsed == AS_ContextSensitiveKeyword;
}
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,12 @@ clang_tablegen(AttrSubMatchRulesList.inc -gen-clang-attr-subject-match-rule-list
SOURCE Attr.td
TARGET ClangAttrSubjectMatchRuleList)

clang_tablegen(AttrTokenKinds.inc -gen-clang-attr-token-kinds
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE Attr.td
TARGET ClangAttrTokenKinds
)

clang_tablegen(AttrHasAttributeImpl.inc -gen-clang-attr-has-attribute-impl
-I ${CMAKE_CURRENT_SOURCE_DIR}/../../
SOURCE Attr.td
Expand Down
4 changes: 3 additions & 1 deletion clang/include/clang/Basic/DiagnosticCommonKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -121,7 +121,7 @@ def note_pragma_entered_here : Note<"#pragma entered here">;
def note_decl_hiding_tag_type : Note<
"%1 %0 is hidden by a non-type declaration of %0 here">;
def err_attribute_not_type_attr : Error<
"%0 attribute cannot be applied to types">;
"%0%select{ attribute|}1 cannot be applied to types">;
def err_enum_template : Error<"enumeration cannot be a template">;

def warn_cxx20_compat_consteval : Warning<
Expand Down Expand Up @@ -175,6 +175,8 @@ def warn_unknown_attribute_ignored : Warning<
"unknown attribute %0 ignored">, InGroup<UnknownAttributes>;
def warn_attribute_ignored : Warning<"%0 attribute ignored">,
InGroup<IgnoredAttributes>;
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">;

Expand Down
17 changes: 12 additions & 5 deletions clang/include/clang/Basic/DiagnosticParseKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -733,10 +733,12 @@ def ext_using_attribute_ns : ExtWarn<
def err_using_attribute_ns_conflict : Error<
"attribute with scope specifier cannot follow default scope specifier">;
def err_attributes_not_allowed : Error<"an attribute list cannot appear here">;
def err_keyword_not_allowed : Error<"%0 cannot appear here">;
def ext_cxx11_attr_placement : ExtWarn<
"ISO C++ does not allow an attribute list to appear here">,
"ISO C++ does not allow %select{an attribute list|%0}1 to appear here">,
InGroup<DiagGroup<"cxx-attribute-extension">>;
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">;
Expand Down Expand Up @@ -1014,14 +1016,15 @@ def err_lambda_capture_multiple_ellipses : Error<
def err_capture_default_first : Error<
"capture default must be first">;
def ext_decl_attrs_on_lambda : ExtWarn<
"an attribute specifier sequence in this position is a C++23 extension">,
InGroup<CXX23>;
"%select{an attribute specifier sequence|%0}1 in this position "
"is a C++23 extension">, InGroup<CXX23>;
def ext_lambda_missing_parens : ExtWarn<
"lambda without a parameter clause is a C++23 extension">,
InGroup<CXX23>;
def warn_cxx20_compat_decl_attrs_on_lambda : Warning<
"an attribute specifier sequence in this position is incompatible with C++ "
"standards before C++23">, InGroup<CXXPre23Compat>, DefaultIgnore;
"%select{an attribute specifier sequence|%1}0 in this position "
"is incompatible with C++ standards before C++23">,
InGroup<CXXPre23Compat>, DefaultIgnore;

// C++17 lambda expressions
def err_expected_star_this_capture : Error<
Expand Down Expand Up @@ -1582,8 +1585,12 @@ def err_module_expected_ident : Error<
"expected a module name after '%select{module|import}0'">;
def err_attribute_not_module_attr : Error<
"%0 attribute cannot be applied to a module">;
def err_keyword_not_module_attr : Error<
"%0 cannot be applied to a module">;
def err_attribute_not_import_attr : Error<
"%0 attribute cannot be applied to a module import">;
def err_keyword_not_import_attr : Error<
"%0 cannot be applied to a module import">;
def err_module_expected_semi : Error<
"expected ';' after module name">;
def err_global_module_introducer_not_at_start : Error<
Expand Down
20 changes: 13 additions & 7 deletions clang/include/clang/Basic/DiagnosticSemaKinds.td
Original file line number Diff line number Diff line change
Expand Up @@ -3022,7 +3022,7 @@ def err_musttail_no_variadic : Error<
def err_nsobject_attribute : Error<
"'NSObject' attribute is for pointer types only">;
def err_attributes_are_not_compatible : Error<
"%0 and %1 attributes are not compatible">;
"%0 and %1%select{ attributes|}2 are not compatible">;
def err_attribute_invalid_argument : Error<
"%select{a reference type|an array type|a non-vector or "
"non-vectorizable scalar type}0 is an invalid argument to attribute %1">;
Expand Down Expand Up @@ -3430,16 +3430,20 @@ def warn_attribute_has_no_effect_on_compile_time_if : Warning<
def note_attribute_has_no_effect_on_compile_time_if_here : Note<
"annotating the 'if %select{constexpr|consteval}0' statement here">;
def err_decl_attribute_invalid_on_stmt : Error<
"%0 attribute cannot be applied to a statement">;
"%0%select{ attribute|}1 cannot be applied to a statement">;
def err_attribute_invalid_on_decl : Error<
"%0 attribute cannot be applied to a declaration">;
"%0%select{ attribute|}1 cannot be applied to a declaration">;
def warn_type_attribute_deprecated_on_decl : Warning<
"applying attribute %0 to a declaration is deprecated; apply it to the type instead">,
InGroup<DeprecatedAttributes>;
def warn_declspec_attribute_ignored : Warning<
"attribute %0 is ignored, place it after "
"\"%select{class|struct|interface|union|enum|enum class|enum struct}1\" to apply attribute to "
"type declaration">, InGroup<IgnoredAttributes>;
def err_declspec_keyword_has_no_effect : Error<
"%0 cannot appear here, place it after "
"\"%select{class|struct|interface|union|enum}1\" to apply it to the "
"type declaration">;
def warn_attribute_precede_definition : Warning<
"attribute declaration must precede definition">,
InGroup<IgnoredAttributes>;
Expand Down Expand Up @@ -3538,11 +3542,11 @@ def err_attribute_weakref_without_alias : Error<
def err_alias_not_supported_on_darwin : Error <
"aliases are not supported on darwin">;
def warn_attribute_wrong_decl_type_str : Warning<
"%0 attribute only applies to %1">, InGroup<IgnoredAttributes>;
"%0%select{ attribute|}1 only applies to %2">, InGroup<IgnoredAttributes>;
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"
Expand All @@ -3555,13 +3559,15 @@ def warn_attribute_wrong_decl_type : Warning<
"|types and namespaces"
"|variables, functions and classes"
"|kernel functions"
"|non-K&R-style functions}1">,
"|non-K&R-style functions}2">,
InGroup<IgnoredAttributes>;
def err_attribute_wrong_decl_type : Error<warn_attribute_wrong_decl_type.Summary>;
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<IgnoredAttributes>;
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<DiagGroup<"encode-type">>;
Expand Down Expand Up @@ -3612,7 +3618,7 @@ def err_invalid_pcs : Error<"invalid PCS type">;
def warn_attribute_not_on_decl : Warning<
"%0 attribute ignored when parsing type">, InGroup<IgnoredAttributes>;
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<IgnoredAttributes>;
Expand Down
6 changes: 6 additions & 0 deletions clang/include/clang/Basic/TokenKinds.def
Original file line number Diff line number Diff line change
Expand Up @@ -748,6 +748,12 @@ KEYWORD(__builtin_bit_cast , KEYALL)
KEYWORD(__builtin_available , KEYALL)
KEYWORD(__builtin_sycl_unique_stable_name, KEYSYCL)

// Keywords defined by Attr.td.
#ifndef KEYWORD_ATTRIBUTE
#define KEYWORD_ATTRIBUTE(X) KEYWORD(X, KEYALL)
#endif
#include "clang/Basic/AttrTokenKinds.inc"

// Clang-specific keywords enabled only in testing.
TESTING_KEYWORD(__unknown_anytype , KEYALL)

Expand Down
7 changes: 7 additions & 0 deletions clang/include/clang/Basic/TokenKinds.h
Original file line number Diff line number Diff line change
Expand Up @@ -99,6 +99,13 @@ bool isAnnotation(TokenKind K);
/// Return true if this is an annotation token representing a pragma.
bool isPragmaAnnotation(TokenKind K);

inline constexpr bool isRegularKeywordAttribute(TokenKind K) {
return (false
#define KEYWORD_ATTRIBUTE(X) || (K == tok::kw_##X)
#include "clang/Basic/AttrTokenKinds.inc"
);
}

} // end namespace tok
} // end namespace clang

Expand Down
9 changes: 7 additions & 2 deletions clang/include/clang/Lex/Token.h
Original file line number Diff line number Diff line change
Expand Up @@ -117,8 +117,13 @@ class Token {
}

/// 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 the token is a keyword that is parsed in the same
/// position as a standard attribute, but that has semantic meaning
/// and so cannot be a true attribute.
bool isRegularKeywordAttribute() const {
return tok::isRegularKeywordAttribute(getKind());
}

/// Return a source location identifier for the specified
Expand Down
40 changes: 27 additions & 13 deletions clang/include/clang/Parse/Parser.h
Original file line number Diff line number Diff line change
Expand Up @@ -2691,6 +2691,18 @@ class Parser : public CodeCompletionHandler {
return LO.DoubleSquareBracketAttributes;
}

/// Return true if the next token should be treated as a [[]] attribute,
/// or as a keyword that behaves like one. The former is only true if
/// [[]] attributes are enabled, whereas the latter is true whenever
/// such a keyword appears. The arguments are as for
/// isCXX11AttributeSpecifier.
bool isAllowedCXX11AttributeSpecifier(bool Disambiguate = false,
bool OuterMightBeMessageSend = false) {
return (Tok.isRegularKeywordAttribute() ||
(standardAttributesAllowed() &&
isCXX11AttributeSpecifier(Disambiguate, OuterMightBeMessageSend)));
}

// Check for the start of an attribute-specifier-seq in a context where an
// attribute is not allowed.
bool CheckProhibitedCXX11Attribute() {
Expand All @@ -2703,11 +2715,13 @@ class Parser : public CodeCompletionHandler {
bool DiagnoseProhibitedCXX11Attribute();
void CheckMisplacedCXX11Attribute(ParsedAttributes &Attrs,
SourceLocation CorrectLocation) {
if (!standardAttributesAllowed())
return;
if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) &&
Tok.isNot(tok::kw_alignas))
return;
if (!Tok.isRegularKeywordAttribute()) {
if (!standardAttributesAllowed())
return;
if ((Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square)) &&
Tok.isNot(tok::kw_alignas))
return;
}
DiagnoseMisplacedCXX11Attribute(Attrs, CorrectLocation);
}
void DiagnoseMisplacedCXX11Attribute(ParsedAttributes &Attrs,
Expand All @@ -2721,18 +2735,18 @@ class Parser : public CodeCompletionHandler {
SourceLocation FixItLoc = SourceLocation()) {
if (Attrs.Range.isInvalid())
return;
DiagnoseProhibitedAttributes(Attrs.Range, FixItLoc);
DiagnoseProhibitedAttributes(Attrs, FixItLoc);
Attrs.clear();
}

void ProhibitAttributes(ParsedAttributesView &Attrs,
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
Expand All @@ -2741,7 +2755,8 @@ class Parser : public CodeCompletionHandler {
// For the most cases we don't want to warn on unknown type attributes, but
// left them to later diagnoses. However, for a few cases like module
// declarations and module import declarations, we should do it.
void ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID,
void ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned AttrDiagID,
unsigned KeywordDiagId,
bool DiagnoseEmptyAttrs = false,
bool WarnOnUnknownAttrs = false);

Expand Down Expand Up @@ -2795,7 +2810,7 @@ class Parser : public CodeCompletionHandler {
bool MaybeParseAttributes(unsigned WhichAttrKinds, ParsedAttributes &Attrs,
LateParsedAttrList *LateAttrs = nullptr) {
if (Tok.isOneOf(tok::kw___attribute, tok::kw___declspec) ||
(standardAttributesAllowed() && isCXX11AttributeSpecifier())) {
isAllowedCXX11AttributeSpecifier()) {
ParseAttributes(WhichAttrKinds, Attrs, LateAttrs);
return true;
}
Expand Down Expand Up @@ -2847,7 +2862,7 @@ class Parser : public CodeCompletionHandler {
}
}
void MaybeParseCXX11Attributes(Declarator &D) {
if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
if (isAllowedCXX11AttributeSpecifier()) {
ParsedAttributes Attrs(AttrFactory);
ParseCXX11Attributes(Attrs);
D.takeAttributes(Attrs);
Expand All @@ -2856,8 +2871,7 @@ class Parser : public CodeCompletionHandler {

bool MaybeParseCXX11Attributes(ParsedAttributes &Attrs,
bool OuterMightBeMessageSend = false) {
if (standardAttributesAllowed() &&
isCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) {
if (isAllowedCXX11AttributeSpecifier(false, OuterMightBeMessageSend)) {
ParseCXX11Attributes(Attrs);
return true;
}
Expand Down
13 changes: 3 additions & 10 deletions clang/include/clang/Sema/DeclSpec.h
Original file line number Diff line number Diff line change
Expand Up @@ -1972,9 +1972,10 @@ class Declarator {
InventedTemplateParameterList(nullptr) {
assert(llvm::all_of(DeclarationAttrs,
[](const ParsedAttr &AL) {
return AL.isStandardAttributeSyntax();
return (AL.isStandardAttributeSyntax() ||
AL.isRegularKeywordAttribute());
}) &&
"DeclarationAttrs may only contain [[]] attributes");
"DeclarationAttrs may only contain [[]] and keyword attributes");
}

~Declarator() {
Expand Down Expand Up @@ -2619,14 +2620,6 @@ class Declarator {
return false;
}

/// Return a source range list of C++11 attributes associated
/// with the declarator.
void getCXX11AttributeRanges(SmallVectorImpl<SourceRange> &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; }

Expand Down
6 changes: 6 additions & 0 deletions clang/lib/AST/TypePrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1757,6 +1757,11 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
return;
}

if (T->getAttrKind() == attr::ArmStreaming) {
OS << "__arm_streaming";
return;
}

OS << " __attribute__((";
switch (T->getAttrKind()) {
#define TYPE_ATTR(NAME)
Expand Down Expand Up @@ -1797,6 +1802,7 @@ void TypePrinter::printAttributedAfter(const AttributedType *T,
case attr::CmseNSCall:
case attr::AnnotateType:
case attr::WebAssemblyFuncref:
case attr::ArmStreaming:
llvm_unreachable("This attribute should have been handled already");

case attr::NSReturnsRetained:
Expand Down
77 changes: 54 additions & 23 deletions clang/lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1693,30 +1693,43 @@ bool Parser::DiagnoseProhibitedCXX11Attribute() {
void Parser::DiagnoseMisplacedCXX11Attribute(ParsedAttributes &Attrs,
SourceLocation CorrectLocation) {
assert((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) ||
Tok.is(tok::kw_alignas));
Tok.is(tok::kw_alignas) || Tok.isRegularKeywordAttribute());

// Consume the attributes.
auto Keyword =
Tok.isRegularKeywordAttribute() ? Tok.getIdentifierInfo() : nullptr;
SourceLocation Loc = Tok.getLocation();
ParseCXX11Attributes(Attrs);
CharSourceRange AttrRange(SourceRange(Loc, Attrs.Range.getEnd()), true);
// FIXME: use err_attributes_misplaced
Diag(Loc, diag::err_attributes_not_allowed)
<< FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange)
<< FixItHint::CreateRemoval(AttrRange);
(Keyword ? Diag(Loc, diag::err_keyword_not_allowed) << Keyword
: Diag(Loc, diag::err_attributes_not_allowed))
<< FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange)
<< FixItHint::CreateRemoval(AttrRange);
}

void Parser::DiagnoseProhibitedAttributes(
const SourceRange &Range, const SourceLocation CorrectLocation) {
const ParsedAttributesView &Attrs, const SourceLocation CorrectLocation) {
auto *FirstAttr = Attrs.empty() ? nullptr : &Attrs.front();
if (CorrectLocation.isValid()) {
CharSourceRange AttrRange(Range, true);
Diag(CorrectLocation, diag::err_attributes_misplaced)
CharSourceRange AttrRange(Attrs.Range, true);
(FirstAttr && FirstAttr->isRegularKeywordAttribute()
? Diag(CorrectLocation, diag::err_keyword_misplaced) << FirstAttr
: Diag(CorrectLocation, diag::err_attributes_misplaced))
<< FixItHint::CreateInsertionFromRange(CorrectLocation, AttrRange)
<< FixItHint::CreateRemoval(AttrRange);
} else
Diag(Range.getBegin(), diag::err_attributes_not_allowed) << Range;
} else {
const SourceRange &Range = Attrs.Range;
(FirstAttr && FirstAttr->isRegularKeywordAttribute()
? Diag(Range.getBegin(), diag::err_keyword_not_allowed) << FirstAttr
: Diag(Range.getBegin(), diag::err_attributes_not_allowed))
<< Range;
}
}

void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID,
void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs,
unsigned AttrDiagID,
unsigned KeywordDiagID,
bool DiagnoseEmptyAttrs,
bool WarnOnUnknownAttrs) {

Expand All @@ -1736,30 +1749,37 @@ void Parser::ProhibitCXX11Attributes(ParsedAttributes &Attrs, unsigned DiagID,
// The attribute range starts with [[, but is empty. So this must
// be [[]], which we are supposed to diagnose because
// DiagnoseEmptyAttrs is true.
Diag(Attrs.Range.getBegin(), DiagID) << Attrs.Range;
Diag(Attrs.Range.getBegin(), AttrDiagID) << Attrs.Range;
return;
}
}
}

for (const ParsedAttr &AL : Attrs) {
if (AL.isRegularKeywordAttribute()) {
Diag(AL.getLoc(), KeywordDiagID) << AL;
AL.setInvalid();
continue;
}
if (!AL.isCXX11Attribute() && !AL.isC2xAttribute())
continue;
if (AL.getKind() == ParsedAttr::UnknownAttribute) {
if (WarnOnUnknownAttrs)
Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored)
<< AL << AL.getRange();
} else {
Diag(AL.getLoc(), DiagID) << AL;
Diag(AL.getLoc(), AttrDiagID) << AL;
AL.setInvalid();
}
}
}

void Parser::DiagnoseCXX11AttributeExtension(ParsedAttributes &Attrs) {
for (const ParsedAttr &PA : Attrs) {
if (PA.isCXX11Attribute() || PA.isC2xAttribute())
Diag(PA.getLoc(), diag::ext_cxx11_attr_placement) << PA << PA.getRange();
if (PA.isCXX11Attribute() || PA.isC2xAttribute() ||
PA.isRegularKeywordAttribute())
Diag(PA.getLoc(), diag::ext_cxx11_attr_placement)
<< PA << PA.isRegularKeywordAttribute() << PA.getRange();
}
}

Expand Down Expand Up @@ -1991,11 +2011,11 @@ bool Parser::MightBeDeclarator(DeclaratorContext Context) {
return getLangOpts().CPlusPlus11 && isCXX11VirtSpecifier(NextToken());

default:
return false;
return Tok.isRegularKeywordAttribute();
}

default:
return false;
return Tok.isRegularKeywordAttribute();
}
}

Expand Down Expand Up @@ -3298,13 +3318,17 @@ void Parser::ParseDeclarationSpecifiers(

switch (Tok.getKind()) {
default:
if (Tok.isRegularKeywordAttribute())
goto Attribute;

DoneWithDeclSpec:
if (!AttrsLastTime)
ProhibitAttributes(attrs);
else {
// Reject C++11 / C2x attributes that aren't type attributes.
for (const ParsedAttr &PA : attrs) {
if (!PA.isCXX11Attribute() && !PA.isC2xAttribute())
if (!PA.isCXX11Attribute() && !PA.isC2xAttribute() &&
!PA.isRegularKeywordAttribute())
continue;
if (PA.getKind() == ParsedAttr::UnknownAttribute)
// We will warn about the unknown attribute elsewhere (in
Expand All @@ -3323,7 +3347,8 @@ void Parser::ParseDeclarationSpecifiers(
if (PA.isTypeAttr() && PA.getKind() != ParsedAttr::AT_LifetimeBound &&
PA.getKind() != ParsedAttr::AT_AnyX86NoCfCheck)
continue;
Diag(PA.getLoc(), diag::err_attribute_not_type_attr) << PA;
Diag(PA.getLoc(), diag::err_attribute_not_type_attr)
<< PA << PA.isRegularKeywordAttribute();
PA.setInvalid();
}

Expand All @@ -3337,9 +3362,10 @@ void Parser::ParseDeclarationSpecifiers(

case tok::l_square:
case tok::kw_alignas:
if (!standardAttributesAllowed() || !isCXX11AttributeSpecifier())
if (!isAllowedCXX11AttributeSpecifier())
goto DoneWithDeclSpec;

Attribute:
ProhibitAttributes(attrs);
// FIXME: It would be good to recover by accepting the attributes,
// but attempting to do that now would cause serious
Expand Down Expand Up @@ -5015,6 +5041,7 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, DeclSpec &DS,
if (IsElaboratedTypeSpecifier && !getLangOpts().MicrosoftExt &&
!getLangOpts().ObjC) {
ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
diag::err_keyword_not_allowed,
/*DiagnoseEmptyAttrs=*/true);
if (BaseType.isUsable())
Diag(BaseRange.getBegin(), diag::ext_enum_base_in_type_specifier)
Expand Down Expand Up @@ -5160,7 +5187,7 @@ void Parser::ParseEnumBody(SourceLocation StartLoc, Decl *EnumDecl) {
// If attributes exist after the enumerator, parse them.
ParsedAttributes attrs(AttrFactory);
MaybeParseGNUAttributes(attrs);
if (standardAttributesAllowed() && isCXX11AttributeSpecifier()) {
if (isAllowedCXX11AttributeSpecifier()) {
if (getLangOpts().CPlusPlus)
Diag(Tok.getLocation(), getLangOpts().CPlusPlus17
? diag::warn_cxx14_compat_ns_enum_attribute
Expand Down Expand Up @@ -5885,8 +5912,8 @@ void Parser::ParseTypeQualifierListOpt(
DeclSpec &DS, unsigned AttrReqs, bool AtomicAllowed,
bool IdentifierRequired,
std::optional<llvm::function_ref<void()>> CodeCompletionHandler) {
if (standardAttributesAllowed() && (AttrReqs & AR_CXX11AttributesParsed) &&
isCXX11AttributeSpecifier()) {
if ((AttrReqs & AR_CXX11AttributesParsed) &&
isAllowedCXX11AttributeSpecifier()) {
ParsedAttributes Attrs(AttrFactory);
ParseCXX11Attributes(Attrs);
DS.takeAttributesFrom(Attrs);
Expand Down Expand Up @@ -6660,6 +6687,10 @@ void Parser::ParseDirectDeclarator(Declarator &D) {
PrototypeScope.Exit();
} else if (Tok.is(tok::l_square)) {
ParseBracketDeclarator(D);
} else if (Tok.isRegularKeywordAttribute()) {
// For consistency with attribute parsing.
Diag(Tok, diag::err_keyword_not_allowed) << Tok.getIdentifierInfo();
ConsumeToken();
} else if (Tok.is(tok::kw_requires) && D.hasGroupingParens()) {
// This declarator is declaring a function, but the requires clause is
// in the wrong place:
Expand Down Expand Up @@ -7064,7 +7095,7 @@ void Parser::ParseFunctionDeclarator(Declarator &D,
TrailingReturnTypeLoc = Range.getBegin();
EndLoc = Range.getEnd();
}
} else if (standardAttributesAllowed()) {
} else {
MaybeParseCXX11Attributes(FnAttrs);
}
}
Expand Down
63 changes: 49 additions & 14 deletions clang/lib/Parse/ParseDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -635,6 +635,7 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
Tok.is(tok::identifier) &&
(NextToken().is(tok::semi) || NextToken().is(tok::comma) ||
NextToken().is(tok::ellipsis) || NextToken().is(tok::l_square) ||
NextToken().isRegularKeywordAttribute() ||
NextToken().is(tok::kw___attribute)) &&
D.SS.isNotEmpty() && LastII == Tok.getIdentifierInfo() &&
!D.SS.getScopeRep()->getAsNamespace() &&
Expand Down Expand Up @@ -767,11 +768,15 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
// If we had any misplaced attributes from earlier, this is where they
// should have been written.
if (MisplacedAttrs.Range.isValid()) {
Diag(MisplacedAttrs.Range.getBegin(), diag::err_attributes_not_allowed)
auto *FirstAttr =
MisplacedAttrs.empty() ? nullptr : &MisplacedAttrs.front();
auto &Range = MisplacedAttrs.Range;
(FirstAttr && FirstAttr->isRegularKeywordAttribute()
? Diag(Range.getBegin(), diag::err_keyword_not_allowed) << FirstAttr
: Diag(Range.getBegin(), diag::err_attributes_not_allowed))
<< FixItHint::CreateInsertionFromRange(
Tok.getLocation(),
CharSourceRange::getTokenRange(MisplacedAttrs.Range))
<< FixItHint::CreateRemoval(MisplacedAttrs.Range);
Tok.getLocation(), CharSourceRange::getTokenRange(Range))
<< FixItHint::CreateRemoval(Range);
Attrs.takeAllFrom(MisplacedAttrs);
}

Expand Down Expand Up @@ -1384,6 +1389,8 @@ bool Parser::isValidAfterTypeSpecifier(bool CouldBeBitfield) {
// This switch enumerates the valid "follow" set for type-specifiers.
switch (Tok.getKind()) {
default:
if (Tok.isRegularKeywordAttribute())
return true;
break;
case tok::semi: // struct foo {...} ;
case tok::star: // struct foo {...} * P;
Expand Down Expand Up @@ -1841,6 +1848,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else if (isClassCompatibleKeyword() &&
(NextToken().is(tok::l_square) ||
NextToken().is(tok::kw_alignas) ||
NextToken().isRegularKeywordAttribute() ||
isCXX11VirtSpecifier(NextToken()) != VirtSpecifiers::VS_None)) {
// We can't tell if this is a definition or reference
// until we skipped the 'final' and C++11 attribute specifiers.
Expand All @@ -1862,6 +1870,8 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
ConsumeParen();
if (!SkipUntil(tok::r_paren, StopAtSemi))
break;
} else if (Tok.isRegularKeywordAttribute()) {
ConsumeToken();
} else {
break;
}
Expand Down Expand Up @@ -1898,7 +1908,11 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
// them to the right place.
SourceRange AttrRange = Attributes.Range;
if (AttrRange.isValid()) {
Diag(AttrRange.getBegin(), diag::err_attributes_not_allowed)
auto *FirstAttr = Attributes.empty() ? nullptr : &Attributes.front();
auto Loc = AttrRange.getBegin();
(FirstAttr && FirstAttr->isRegularKeywordAttribute()
? Diag(Loc, diag::err_keyword_not_allowed) << FirstAttr
: Diag(Loc, diag::err_attributes_not_allowed))
<< AttrRange
<< FixItHint::CreateInsertionFromRange(
AttrFixitLoc, CharSourceRange(AttrRange, true))
Expand Down Expand Up @@ -1946,6 +1960,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
TUK == Sema::TUK_Declaration) {
// This is an explicit instantiation of a class template.
ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
diag::err_keyword_not_allowed,
/*DiagnoseEmptyAttrs=*/true);

TagOrTempResult = Actions.ActOnExplicitInstantiation(
Expand All @@ -1962,6 +1977,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
(TUK == Sema::TUK_Friend &&
TemplateInfo.Kind == ParsedTemplateInfo::NonTemplate)) {
ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
diag::err_keyword_not_allowed,
/*DiagnoseEmptyAttrs=*/true);
TypeResult = Actions.ActOnTagTemplateIdType(
TUK, TagType, StartLoc, SS, TemplateId->TemplateKWLoc,
Expand Down Expand Up @@ -2031,6 +2047,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else if (TUK == Sema::TUK_Friend &&
TemplateInfo.Kind != ParsedTemplateInfo::NonTemplate) {
ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
diag::err_keyword_not_allowed,
/*DiagnoseEmptyAttrs=*/true);

TagOrTempResult = Actions.ActOnTemplatedFriendTag(
Expand All @@ -2041,6 +2058,7 @@ void Parser::ParseClassSpecifier(tok::TokenKind TagTokKind,
} else {
if (TUK != Sema::TUK_Declaration && TUK != Sema::TUK_Definition)
ProhibitCXX11Attributes(attrs, diag::err_attributes_not_allowed,
diag::err_keyword_not_allowed,
/* DiagnoseEmptyAttrs=*/true);

if (TUK == Sema::TUK_Definition &&
Expand Down Expand Up @@ -3017,12 +3035,14 @@ Parser::ParseCXXClassMemberDeclaration(AccessSpecifier AS,
//
// Diagnose attributes that appear in a friend member function declarator:
// friend int foo [[]] ();
SmallVector<SourceRange, 4> Ranges;
DeclaratorInfo.getCXX11AttributeRanges(Ranges);
for (SmallVectorImpl<SourceRange>::iterator I = Ranges.begin(),
E = Ranges.end();
I != E; ++I)
Diag((*I).getBegin(), diag::err_attributes_not_allowed) << *I;
for (const ParsedAttr &AL : DeclaratorInfo.getAttributes())
if (AL.isCXX11Attribute() || AL.isRegularKeywordAttribute()) {
auto Loc = AL.getRange().getBegin();
(AL.isRegularKeywordAttribute()
? Diag(Loc, diag::err_keyword_not_allowed) << AL
: Diag(Loc, diag::err_attributes_not_allowed))
<< AL.getRange();
}

ThisDecl = Actions.ActOnFriendFunctionDecl(getCurScope(), DeclaratorInfo,
TemplateParams);
Expand Down Expand Up @@ -4470,6 +4490,14 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
return;
}

if (Tok.isRegularKeywordAttribute()) {
SourceLocation Loc = Tok.getLocation();
IdentifierInfo *AttrName = Tok.getIdentifierInfo();
Attrs.addNew(AttrName, Loc, nullptr, Loc, nullptr, 0, Tok.getKind());
ConsumeToken();
return;
}

assert(Tok.is(tok::l_square) && NextToken().is(tok::l_square) &&
"Not a double square bracket attribute list");

Expand Down Expand Up @@ -4589,26 +4617,30 @@ void Parser::ParseCXX11AttributeSpecifierInternal(ParsedAttributes &Attrs,
/// attribute-specifier-seq:
/// attribute-specifier-seq[opt] attribute-specifier
void Parser::ParseCXX11Attributes(ParsedAttributes &Attrs) {
assert(standardAttributesAllowed());
assert(standardAttributesAllowed() || Tok.isRegularKeywordAttribute());

SourceLocation StartLoc = Tok.getLocation();
SourceLocation EndLoc = StartLoc;

do {
ParseCXX11AttributeSpecifier(Attrs, &EndLoc);
} while (isCXX11AttributeSpecifier());
} while (isAllowedCXX11AttributeSpecifier());

Attrs.Range = SourceRange(StartLoc, EndLoc);
}

void Parser::DiagnoseAndSkipCXX11Attributes() {
auto Keyword =
Tok.isRegularKeywordAttribute() ? Tok.getIdentifierInfo() : nullptr;
// Start and end location of an attribute or an attribute list.
SourceLocation StartLoc = Tok.getLocation();
SourceLocation EndLoc = SkipCXX11Attributes();

if (EndLoc.isValid()) {
SourceRange Range(StartLoc, EndLoc);
Diag(StartLoc, diag::err_attributes_not_allowed) << Range;
(Keyword ? Diag(StartLoc, diag::err_keyword_not_allowed) << Keyword
: Diag(StartLoc, diag::err_attributes_not_allowed))
<< Range;
}
}

Expand All @@ -4624,6 +4656,9 @@ SourceLocation Parser::SkipCXX11Attributes() {
T.consumeOpen();
T.skipToEnd();
EndLoc = T.getCloseLocation();
} else if (Tok.isRegularKeywordAttribute()) {
EndLoc = Tok.getLocation();
ConsumeToken();
} else {
assert(Tok.is(tok::kw_alignas) && "not an attribute specifier");
ConsumeToken();
Expand Down
4 changes: 3 additions & 1 deletion clang/lib/Parse/ParseExprCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1364,7 +1364,8 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
if (isCXX11AttributeSpecifier()) {
Diag(Tok, getLangOpts().CPlusPlus23
? diag::warn_cxx20_compat_decl_attrs_on_lambda
: diag::ext_decl_attrs_on_lambda);
: diag::ext_decl_attrs_on_lambda)
<< Tok.getIdentifierInfo() << Tok.isRegularKeywordAttribute();
MaybeParseCXX11Attributes(D);
}

Expand Down Expand Up @@ -1499,6 +1500,7 @@ ExprResult Parser::ParseLambdaExpressionAfterIntroducer(
tok::kw___private, tok::kw___global, tok::kw___local,
tok::kw___constant, tok::kw___generic, tok::kw_groupshared,
tok::kw_requires, tok::kw_noexcept) ||
Tok.isRegularKeywordAttribute() ||
(Tok.is(tok::l_square) && NextToken().is(tok::l_square));

if (HasSpecifiers && !HasParentheses && !getLangOpts().CPlusPlus23) {
Expand Down
3 changes: 2 additions & 1 deletion clang/lib/Parse/ParsePragma.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1819,7 +1819,8 @@ void Parser::HandlePragmaAttribute() {
ConsumeToken();
};

if (Tok.is(tok::l_square) && NextToken().is(tok::l_square)) {
if ((Tok.is(tok::l_square) && NextToken().is(tok::l_square)) ||
Tok.isRegularKeywordAttribute()) {
// Parse the CXX11 style attribute.
ParseCXX11AttributeSpecifier(Attrs);
} else if (Tok.is(tok::kw___attribute)) {
Expand Down
7 changes: 6 additions & 1 deletion clang/lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,12 @@ StmtResult Parser::ParseStatementOrDeclarationAfterAttributes(

case tok::kw_asm: {
for (const ParsedAttr &AL : CXX11Attrs)
Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored) << AL;
// Could be relaxed if asm-related regular keyword attributes are
// added later.
(AL.isRegularKeywordAttribute()
? Diag(AL.getRange().getBegin(), diag::err_keyword_not_allowed)
: Diag(AL.getRange().getBegin(), diag::warn_attribute_ignored))
<< AL;
// Prevent these from being interpreted as statement attributes later on.
CXX11Attrs.clear();
ProhibitAttributes(GNUAttrs);
Expand Down
8 changes: 7 additions & 1 deletion clang/lib/Parse/ParseTentative.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -723,6 +723,9 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,
if (Tok.is(tok::kw_alignas))
return CAK_AttributeSpecifier;

if (Tok.isRegularKeywordAttribute())
return CAK_AttributeSpecifier;

if (Tok.isNot(tok::l_square) || NextToken().isNot(tok::l_square))
return CAK_NotAttributeSpecifier;

Expand Down Expand Up @@ -862,7 +865,8 @@ Parser::isCXX11AttributeSpecifier(bool Disambiguate,

bool Parser::TrySkipAttributes() {
while (Tok.isOneOf(tok::l_square, tok::kw___attribute, tok::kw___declspec,
tok::kw_alignas)) {
tok::kw_alignas) ||
Tok.isRegularKeywordAttribute()) {
if (Tok.is(tok::l_square)) {
ConsumeBracket();
if (Tok.isNot(tok::l_square))
Expand All @@ -873,6 +877,8 @@ bool Parser::TrySkipAttributes() {
// Note that explicitly checking for `[[` and `]]` allows to fail as
// expected in the case of the Objective-C message send syntax.
ConsumeBracket();
} else if (Tok.isRegularKeywordAttribute()) {
ConsumeToken();
} else {
ConsumeToken();
if (Tok.isNot(tok::l_paren))
Expand Down
2 changes: 2 additions & 0 deletions clang/lib/Parse/Parser.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2461,6 +2461,7 @@ Parser::ParseModuleDecl(Sema::ModuleImportState &ImportState) {
ParsedAttributes Attrs(AttrFactory);
MaybeParseCXX11Attributes(Attrs);
ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_module_attr,
diag::err_keyword_not_module_attr,
/*DiagnoseEmptyAttrs=*/false,
/*WarnOnUnknownAttrs=*/true);

Expand Down Expand Up @@ -2530,6 +2531,7 @@ Decl *Parser::ParseModuleImport(SourceLocation AtLoc,
MaybeParseCXX11Attributes(Attrs);
// We don't support any module import attributes yet.
ProhibitCXX11Attributes(Attrs, diag::err_attribute_not_import_attr,
diag::err_keyword_not_import_attr,
/*DiagnoseEmptyAttrs=*/false,
/*WarnOnUnknownAttrs=*/true);

Expand Down
5 changes: 5 additions & 0 deletions clang/lib/Sema/ParsedAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -203,6 +203,11 @@ bool ParsedAttr::isSupportedByPragmaAttribute() const {
}

bool ParsedAttr::slidesFromDeclToDeclSpecLegacyBehavior() const {
if (isRegularKeywordAttribute())
// The appurtenance rules are applied strictly for all regular keyword
// atributes.
return false;

assert(isStandardAttributeSyntax());

// We have historically allowed some type attributes with standard attribute
Expand Down
2 changes: 1 addition & 1 deletion clang/lib/Sema/Sema.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1184,7 +1184,7 @@ void Sema::ActOnEndOfTranslationUnit() {
!(isa<FunctionDecl>(PrevDecl) || isa<VarDecl>(PrevDecl)))
for (const auto &WI : WeakIDs.second)
Diag(WI.getLocation(), diag::warn_attribute_wrong_decl_type)
<< "'weak'" << ExpectedVariableOrFunction;
<< "'weak'" << /*isRegularKeyword=*/0 << ExpectedVariableOrFunction;
else
for (const auto &WI : WeakIDs.second)
Diag(WI.getLocation(), diag::warn_weak_identifier_undeclared)
Expand Down
8 changes: 6 additions & 2 deletions clang/lib/Sema/SemaDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5315,10 +5315,14 @@ Decl *Sema::ParsedFreeStandingDeclSpec(Scope *S, AccessSpecifier AS,
TypeSpecType == DeclSpec::TST_union ||
TypeSpecType == DeclSpec::TST_enum) {
for (const ParsedAttr &AL : DS.getAttributes())
Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored)
Diag(AL.getLoc(), AL.isRegularKeywordAttribute()
? diag::err_declspec_keyword_has_no_effect
: diag::warn_declspec_attribute_ignored)
<< AL << GetDiagnosticTypeSpecifierID(DS);
for (const ParsedAttr &AL : DeclAttrs)
Diag(AL.getLoc(), diag::warn_declspec_attribute_ignored)
Diag(AL.getLoc(), AL.isRegularKeywordAttribute()
? diag::err_declspec_keyword_has_no_effect
: diag::warn_declspec_attribute_ignored)
<< AL << GetDiagnosticTypeSpecifierID(DS);
}
}
Expand Down
142 changes: 88 additions & 54 deletions clang/lib/Sema/SemaDeclAttr.cpp

Large diffs are not rendered by default.

10 changes: 6 additions & 4 deletions clang/lib/Sema/SemaDeclCXX.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2710,10 +2710,12 @@ BaseResult Sema::ActOnBaseSpecifier(Decl *classdecl, SourceRange SpecifierRange,
for (const ParsedAttr &AL : Attributes) {
if (AL.isInvalid() || AL.getKind() == ParsedAttr::IgnoredAttribute)
continue;
Diag(AL.getLoc(), AL.getKind() == ParsedAttr::UnknownAttribute
? (unsigned)diag::warn_unknown_attribute_ignored
: (unsigned)diag::err_base_specifier_attribute)
<< AL << AL.getRange();
if (AL.getKind() == ParsedAttr::UnknownAttribute)
Diag(AL.getLoc(), diag::warn_unknown_attribute_ignored)
<< AL << AL.getRange();
else
Diag(AL.getLoc(), diag::err_base_specifier_attribute)
<< AL << AL.isRegularKeywordAttribute() << AL.getRange();
}

TypeSourceInfo *TInfo = nullptr;
Expand Down
6 changes: 4 additions & 2 deletions clang/lib/Sema/SemaStmtAttr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -490,7 +490,9 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
!(A.existsInTarget(S.Context.getTargetInfo()) ||
(S.Context.getLangOpts().SYCLIsDevice && Aux &&
A.existsInTarget(*Aux)))) {
S.Diag(A.getLoc(), A.isDeclspecAttribute()
S.Diag(A.getLoc(), A.isRegularKeywordAttribute()
? (unsigned)diag::err_keyword_not_supported_on_target
: A.isDeclspecAttribute()
? (unsigned)diag::warn_unhandled_ms_attribute_ignored
: (unsigned)diag::warn_unknown_attribute_ignored)
<< A << A.getRange();
Expand Down Expand Up @@ -526,7 +528,7 @@ static Attr *ProcessStmtAttribute(Sema &S, Stmt *St, const ParsedAttr &A,
// declaration attribute is not written on a statement, but this code is
// needed for attributes in Attr.td that do not list any subjects.
S.Diag(A.getRange().getBegin(), diag::err_decl_attribute_invalid_on_stmt)
<< A << St->getBeginLoc();
<< A << A.isRegularKeywordAttribute() << St->getBeginLoc();
return nullptr;
}
}
Expand Down
45 changes: 29 additions & 16 deletions clang/lib/Sema/SemaType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -103,8 +103,10 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
}
}

S.Diag(loc, diag::warn_type_attribute_wrong_type) << name << WhichType
<< type;
S.Diag(loc, attr.isRegularKeywordAttribute()
? diag::err_type_attribute_wrong_type
: diag::warn_type_attribute_wrong_type)
<< name << WhichType << type;
}

// objc_gc applies to Objective-C pointers or, otherwise, to the
Expand All @@ -126,6 +128,7 @@ static void diagnoseBadTypeAttribute(Sema &S, const ParsedAttr &attr,
case ParsedAttr::AT_VectorCall: \
case ParsedAttr::AT_AArch64VectorPcs: \
case ParsedAttr::AT_AArch64SVEPcs: \
case ParsedAttr::AT_ArmStreaming: \
case ParsedAttr::AT_AMDGPUKernelCall: \
case ParsedAttr::AT_MSABI: \
case ParsedAttr::AT_SysVABI: \
Expand Down Expand Up @@ -684,7 +687,7 @@ static void distributeTypeAttrsFromDeclarator(TypeProcessingState &state,
for (ParsedAttr &attr : AttrsCopy) {
// Do not distribute [[]] attributes. They have strict rules for what
// they appertain to.
if (attr.isStandardAttributeSyntax())
if (attr.isStandardAttributeSyntax() || attr.isRegularKeywordAttribute())
continue;

switch (attr.getKind()) {
Expand Down Expand Up @@ -4895,8 +4898,10 @@ static TypeSourceInfo *GetFullTypeForDeclarator(TypeProcessingState &state,
// If we're supposed to infer nullability, do so now.
if (inferNullability && !inferNullabilityInnerOnlyComplete) {
ParsedAttr::Form form =
inferNullabilityCS ? ParsedAttr::Form::ContextSensitiveKeyword()
: ParsedAttr::Form::Keyword(false /*IsAlignAs*/);
inferNullabilityCS
? ParsedAttr::Form::ContextSensitiveKeyword()
: ParsedAttr::Form::Keyword(false /*IsAlignAs*/,
false /*IsRegularKeywordAttribute*/);
ParsedAttr *nullabilityAttr = Pool.create(
S.getNullabilityKeyword(*inferNullability), SourceRange(pointerLoc),
nullptr, SourceLocation(), nullptr, 0, form);
Expand Down Expand Up @@ -7331,12 +7336,12 @@ static bool handleMSPointerTypeQualifierAttr(TypeProcessingState &State,
if (Attrs[attr::Ptr32] && Attrs[attr::Ptr64]) {
S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
<< "'__ptr32'"
<< "'__ptr64'";
<< "'__ptr64'" << /*isRegularKeyword=*/0;
return true;
} else if (Attrs[attr::SPtr] && Attrs[attr::UPtr]) {
S.Diag(PAttr.getLoc(), diag::err_attributes_are_not_compatible)
<< "'__sptr'"
<< "'__uptr'";
<< "'__uptr'" << /*isRegularKeyword=*/0;
return true;
}

Expand Down Expand Up @@ -7710,6 +7715,8 @@ static Attr *getCCTypeAttr(ASTContext &Ctx, ParsedAttr &Attr) {
return createSimpleAttr<AArch64VectorPcsAttr>(Ctx, Attr);
case ParsedAttr::AT_AArch64SVEPcs:
return createSimpleAttr<AArch64SVEPcsAttr>(Ctx, Attr);
case ParsedAttr::AT_ArmStreaming:
return createSimpleAttr<ArmStreamingAttr>(Ctx, Attr);
case ParsedAttr::AT_AMDGPUKernelCall:
return createSimpleAttr<AMDGPUKernelCallAttr>(Ctx, Attr);
case ParsedAttr::AT_Pcs: {
Expand Down Expand Up @@ -7857,8 +7864,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
CallingConv CC = fn->getCallConv();
if (CC == CC_X86FastCall) {
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
<< FunctionType::getNameForCallConv(CC)
<< "regparm";
<< FunctionType::getNameForCallConv(CC) << "regparm"
<< attr.isRegularKeywordAttribute();
attr.setInvalid();
return true;
}
Expand Down Expand Up @@ -7937,8 +7944,9 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
// and the CCs don't match.
if (S.getCallingConvAttributedType(type)) {
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
<< FunctionType::getNameForCallConv(CC)
<< FunctionType::getNameForCallConv(CCOld);
<< FunctionType::getNameForCallConv(CC)
<< FunctionType::getNameForCallConv(CCOld)
<< attr.isRegularKeywordAttribute();
attr.setInvalid();
return true;
}
Expand Down Expand Up @@ -7970,7 +7978,8 @@ static bool handleFunctionTypeAttr(TypeProcessingState &state, ParsedAttr &attr,
// Also diagnose fastcall with regparm.
if (CC == CC_X86FastCall && fn->getHasRegParm()) {
S.Diag(attr.getLoc(), diag::err_attributes_are_not_compatible)
<< "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall);
<< "regparm" << FunctionType::getNameForCallConv(CC_X86FastCall)
<< attr.isRegularKeywordAttribute();
attr.setInvalid();
return true;
}
Expand Down Expand Up @@ -8486,12 +8495,13 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
if (attr.isInvalid())
continue;

if (attr.isStandardAttributeSyntax()) {
if (attr.isStandardAttributeSyntax() || attr.isRegularKeywordAttribute()) {
// [[gnu::...]] attributes are treated as declaration attributes, so may
// not appertain to a DeclaratorChunk. If we handle them as type
// attributes, accept them in that position and diagnose the GCC
// incompatibility.
if (attr.isGNUScope()) {
assert(attr.isStandardAttributeSyntax());
bool IsTypeAttr = attr.isTypeAttr();
if (TAL == TAL_DeclChunk) {
state.getSema().Diag(attr.getLoc(),
Expand Down Expand Up @@ -8519,9 +8529,11 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,
switch (attr.getKind()) {
default:
// A [[]] attribute on a declarator chunk must appertain to a type.
if (attr.isStandardAttributeSyntax() && TAL == TAL_DeclChunk) {
if ((attr.isStandardAttributeSyntax() ||
attr.isRegularKeywordAttribute()) &&
TAL == TAL_DeclChunk) {
state.getSema().Diag(attr.getLoc(), diag::err_attribute_not_type_attr)
<< attr;
<< attr << attr.isRegularKeywordAttribute();
attr.setUsedAsTypeAttr();
}
break;
Expand Down Expand Up @@ -8702,7 +8714,8 @@ static void processTypeAttrs(TypeProcessingState &state, QualType &type,

// Attributes with standard syntax have strict rules for what they
// appertain to and hence should not use the "distribution" logic below.
if (attr.isStandardAttributeSyntax()) {
if (attr.isStandardAttributeSyntax() ||
attr.isRegularKeywordAttribute()) {
if (!handleFunctionTypeAttr(state, attr, type)) {
diagnoseBadTypeAttribute(state.getSema(), attr, type);
attr.setInvalid();
Expand Down
9 changes: 5 additions & 4 deletions clang/lib/Serialization/ASTReaderDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3101,11 +3101,12 @@ Attr *ASTRecordReader::readAttr() {
bool IsAlignas = (ParsedKind == AttributeCommonInfo::AT_Aligned &&
Syntax == AttributeCommonInfo::AS_Keyword &&
SpellingIndex == AlignedAttr::Keyword_alignas);
bool IsRegularKeywordAttribute = Record.readBool();

AttributeCommonInfo Info(
AttrName, ScopeName, AttrRange, ScopeLoc,
AttributeCommonInfo::Kind(ParsedKind),
{AttributeCommonInfo::Syntax(Syntax), SpellingIndex, IsAlignas});
AttributeCommonInfo Info(AttrName, ScopeName, AttrRange, ScopeLoc,
AttributeCommonInfo::Kind(ParsedKind),
{AttributeCommonInfo::Syntax(Syntax), SpellingIndex,
IsAlignas, IsRegularKeywordAttribute});

#include "clang/Serialization/AttrPCHRead.inc"

Expand Down
1 change: 1 addition & 0 deletions clang/lib/Serialization/ASTWriter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4380,6 +4380,7 @@ void ASTRecordWriter::AddAttr(const Attr *A) {
Record.push_back(A->getParsedKind());
Record.push_back(A->getSyntax());
Record.push_back(A->getAttributeSpellingListIndexRaw());
Record.push_back(A->isRegularKeywordAttribute());

#include "clang/Serialization/AttrPCHWrite.inc"
}
Expand Down
119 changes: 119 additions & 0 deletions clang/test/Parser/c2x-attribute-keywords.c
Original file line number Diff line number Diff line change
@@ -0,0 +1,119 @@
// RUN: %clang_cc1 -fsyntax-only -triple aarch64-none-linux-gnu -target-feature +sme -verify=expected,notc2x -Wno-strict-prototypes %s
// RUN: %clang_cc1 -fsyntax-only -triple aarch64-none-linux-gnu -target-feature +sme -verify=expected,c2x %s

enum __arm_streaming E { // expected-error {{'__arm_streaming' cannot be applied to a declaration}}
One __arm_streaming, // expected-error {{'__arm_streaming' cannot be applied to a declaration}}
Two,
Three __arm_streaming // expected-error {{'__arm_streaming' cannot be applied to a declaration}}
};

enum __arm_streaming { Four }; // expected-error {{'__arm_streaming' cannot be applied to a declaration}}
__arm_streaming enum E2 { Five }; // expected-error {{misplaced '__arm_streaming'}}

// FIXME: this diagnostic can be improved.
enum { __arm_streaming Six }; // expected-error {{expected identifier}}

// FIXME: this diagnostic can be improved.
enum E3 __arm_streaming { Seven }; // expected-error {{expected identifier or '('}}

struct __arm_streaming S1 { // expected-error {{'__arm_streaming' cannot be applied to a declaration}}
int i __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}}
int __arm_streaming j; // expected-error {{'__arm_streaming' only applies to function types}}
int k[10] __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}}
int l __arm_streaming[10]; // expected-error {{'__arm_streaming' only applies to function types}}
__arm_streaming int m, n; // expected-error {{'__arm_streaming' only applies to function types}}
int o __arm_streaming : 12; // expected-error {{'__arm_streaming' only applies to function types}}
int __arm_streaming : 0; // expected-error {{'__arm_streaming' only applies to function types}}
int p, __arm_streaming : 0; // expected-error {{'__arm_streaming' cannot appear here}}
int q, __arm_streaming r; // expected-error {{'__arm_streaming' cannot appear here}}
__arm_streaming int; // expected-error {{'__arm_streaming' cannot appear here}} \
// expected-warning {{declaration does not declare anything}}
};

__arm_streaming struct S2 { int a; }; // expected-error {{misplaced '__arm_streaming'}}
struct S3 __arm_streaming { int a; }; // expected-error {{'__arm_streaming' cannot appear here}} \
expected-error {{'__arm_streaming' cannot be applied to a declaration}}

union __arm_streaming U { // expected-error {{'__arm_streaming' cannot be applied to a declaration}}
double d __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types; type here is 'double'}}
__arm_streaming int i; // expected-error {{'__arm_streaming' only applies to function types; type here is 'int'}}
};

__arm_streaming union U2 { double d; }; // expected-error {{misplaced '__arm_streaming'}}
union U3 __arm_streaming { double d; }; // expected-error {{'__arm_streaming' cannot appear here}} \
expected-error {{'__arm_streaming' cannot be applied to a declaration}}

struct __arm_streaming IncompleteStruct; // expected-error {{'__arm_streaming' cannot be applied to a declaration}}
union __arm_streaming IncompleteUnion; // expected-error {{'__arm_streaming' cannot be applied to a declaration}}
enum __arm_streaming IncompleteEnum; // expected-error {{'__arm_streaming' cannot be applied to a declaration}}

__arm_streaming void f1(void); // expected-error {{'__arm_streaming' cannot be applied to a declaration}}
void __arm_streaming f2(void); // expected-error {{'__arm_streaming' only applies to function types}}
void f3 __arm_streaming (void); // expected-error {{'__arm_streaming' cannot be applied to a declaration}}
void f4(void) __arm_streaming;

void f5(int i __arm_streaming, __arm_streaming int j, int __arm_streaming k); // expected-error 3 {{'__arm_streaming' only applies to function types}}

void f6(a, b) __arm_streaming int a; int b; { // expected-error {{'__arm_streaming' cannot appear here}} \
c2x-warning {{deprecated}}
}

// FIXME: technically, an attribute list cannot appear here, but we currently
// parse it as part of the return type of the function, which is reasonable
// behavior given that we *don't* want to parse it as part of the K&R parameter
// declarations. It is disallowed to avoid a parsing ambiguity we already
// handle well.
int (*f7(a, b))(int, int) __arm_streaming int a; int b; { // c2x-warning {{deprecated}}
return 0;
}

__arm_streaming int a, b; // expected-error {{'__arm_streaming' only applies to function types}}
int c __arm_streaming, d __arm_streaming; // expected-error 2 {{'__arm_streaming' only applies to function types}}

void f8(void) __arm_streaming {
__arm_streaming int i, j; // expected-error {{'__arm_streaming' only applies to function types}}
int k, l __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}}
}

__arm_streaming void f9(void) { // expected-error {{'__arm_streaming' cannot be applied to a declaration}}
int i[10] __arm_streaming; // expected-error {{'__arm_streaming' only applies to function types}}
int (*fp1)(void)__arm_streaming;
int (*fp2 __arm_streaming)(void); // expected-error {{'__arm_streaming' cannot be applied to a declaration}}

int * __arm_streaming *ipp; // expected-error {{'__arm_streaming' only applies to function types}}
}

void f10(int j[static 10] __arm_streaming, int k[*] __arm_streaming); // expected-error 2 {{'__arm_streaming' only applies to function types}}

void f11(void) {
__arm_streaming {} // expected-error {{'__arm_streaming' cannot be applied to a statement}}
__arm_streaming if (1) {} // expected-error {{'__arm_streaming' cannot be applied to a statement}}

__arm_streaming switch (1) { // expected-error {{'__arm_streaming' cannot be applied to a statement}}
__arm_streaming case 1: __arm_streaming break; // expected-error 2 {{'__arm_streaming' cannot be applied to a statement}}
__arm_streaming default: break; // expected-error {{'__arm_streaming' cannot be applied to a statement}}
}

goto foo;
__arm_streaming foo: (void)1; // expected-error {{'__arm_streaming' cannot be applied to a declaration}}

__arm_streaming for (;;); // expected-error {{'__arm_streaming' cannot be applied to a statement}}
__arm_streaming while (1); // expected-error {{'__arm_streaming' cannot be applied to a statement}}
__arm_streaming do __arm_streaming { } while(1); // expected-error 2 {{'__arm_streaming' cannot be applied to a statement}}

__arm_streaming (void)1; // expected-error {{'__arm_streaming' cannot be applied to a statement}}

__arm_streaming; // expected-error {{'__arm_streaming' cannot be applied to a statement}}

(void)sizeof(int [4]__arm_streaming); // expected-error {{'__arm_streaming' only applies to function types}}
(void)sizeof(struct __arm_streaming S3 { int a __arm_streaming; }); // expected-error {{'__arm_streaming' cannot be applied to a declaration}} \
// expected-error {{'__arm_streaming' only applies to function types; type here is 'int'}}

__arm_streaming return; // expected-error {{'__arm_streaming' cannot be applied to a statement}}

__arm_streaming asm (""); // expected-error {{'__arm_streaming' cannot appear here}}
}

struct __arm_streaming S4 *s; // expected-error {{'__arm_streaming' cannot appear here}}
struct S5 {};
int c = sizeof(struct __arm_streaming S5); // expected-error {{'__arm_streaming' cannot appear here}}
19 changes: 19 additions & 0 deletions clang/test/Parser/c2x-attribute-keywords.m
Original file line number Diff line number Diff line change
@@ -0,0 +1,19 @@
// RUN: %clang_cc1 -fsyntax-only -triple aarch64-none-linux-gnu -target-feature +sme -verify %s

enum __arm_streaming E1 : int; // expected-error {{'__arm_streaming' cannot be applied to a declaration}}

@interface Base
@end

@interface S : Base
- (void) bar;
@end

@interface T : Base
- (S *) foo;
@end


void f(T *t) {
__arm_streaming[[t foo] bar]; // expected-error {{'__arm_streaming' cannot be applied to a statement}}
}
345 changes: 345 additions & 0 deletions clang/test/Parser/cxx0x-keyword-attributes.cpp

Large diffs are not rendered by default.

12 changes: 12 additions & 0 deletions clang/unittests/AST/AttrTest.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -168,4 +168,16 @@ TEST(Attr, AnnotateType) {
}
}

TEST(Attr, RegularKeywordAttribute) {
auto AST = clang::tooling::buildASTFromCode("");
auto &Ctx = AST->getASTContext();
auto Funcref = clang::WebAssemblyFuncrefAttr::CreateImplicit(Ctx);
EXPECT_EQ(Funcref->getSyntax(), clang::AttributeCommonInfo::AS_Keyword);
ASSERT_FALSE(Funcref->isRegularKeywordAttribute());

auto Streaming = clang::ArmStreamingAttr::CreateImplicit(Ctx);
EXPECT_EQ(Streaming->getSyntax(), clang::AttributeCommonInfo::AS_Keyword);
ASSERT_TRUE(Streaming->isRegularKeywordAttribute());
}

} // namespace
48 changes: 40 additions & 8 deletions clang/utils/TableGen/ClangAttrEmitter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2381,14 +2381,21 @@ static void emitClangAttrAcceptsExprPack(RecordKeeper &Records,
OS << "#endif // CLANG_ATTR_ACCEPTS_EXPR_PACK\n\n";
}

static bool isRegularKeywordAttribute(const FlattenedSpelling &S) {
return (S.variety() == "Keyword" &&
!S.getSpellingRecord().getValueAsBit("HasOwnParseRules"));
}

static void emitFormInitializer(raw_ostream &OS,
const FlattenedSpelling &Spelling,
StringRef SpellingIndex) {
bool IsAlignas =
(Spelling.variety() == "Keyword" && Spelling.name() == "alignas");
OS << "{AttributeCommonInfo::AS_" << Spelling.variety() << ", "
<< SpellingIndex << ", " << (IsAlignas ? "true" : "false")
<< " /*IsAlignas*/}";
<< " /*IsAlignas*/, "
<< (isRegularKeywordAttribute(Spelling) ? "true" : "false")
<< " /*IsRegularKeywordAttribute*/}";
}

static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
Expand Down Expand Up @@ -3407,6 +3414,26 @@ static void GenerateHasAttrSpellingStringSwitch(
OS << " .Default(0);\n";
}

// Emits the list of tokens for regular keyword attributes.
void EmitClangAttrTokenKinds(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("A list of tokens generated from the attribute"
" definitions",
OS);
// Assume for now that the same token is not used in multiple regular
// keyword attributes.
for (auto *R : Records.getAllDerivedDefinitions("Attr"))
for (const auto &S : GetFlattenedSpellings(*R))
if (isRegularKeywordAttribute(S)) {
if (!R->getValueAsListOfDefs("Args").empty())
PrintError(R->getLoc(),
"RegularKeyword attributes with arguments are not "
"yet supported");
OS << "KEYWORD_ATTRIBUTE("
<< S.getSpellingRecord().getValueAsString("Name") << ")\n";
}
OS << "#undef KEYWORD_ATTRIBUTE\n";
}

// Emits the list of spellings for attributes.
void EmitClangAttrHasAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
emitSourceFileHeader("Code to implement the __has_attribute logic", OS);
Expand Down Expand Up @@ -3855,7 +3882,8 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
OS << "bool diagAppertainsToDecl(Sema &S, const ParsedAttr &AL, ";
OS << "const Decl *D) const override {\n";
OS << " S.Diag(AL.getLoc(), diag::err_attribute_invalid_on_decl)\n";
OS << " << AL << D->getLocation();\n";
OS << " << AL << AL.isRegularKeywordAttribute() << "
"D->getLocation();\n";
OS << " return false;\n";
OS << "}\n\n";
}
Expand Down Expand Up @@ -3884,7 +3912,7 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
OS << (Warn ? "warn_attribute_wrong_decl_type_str"
: "err_attribute_wrong_decl_type_str");
OS << ")\n";
OS << " << Attr << ";
OS << " << Attr << Attr.isRegularKeywordAttribute() << ";
OS << CalculateDiagnostic(*SubjectObj) << ";\n";
OS << " return false;\n";
OS << " }\n";
Expand All @@ -3899,7 +3927,8 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
OS << "bool diagAppertainsToStmt(Sema &S, const ParsedAttr &AL, ";
OS << "const Stmt *St) const override {\n";
OS << " S.Diag(AL.getLoc(), diag::err_decl_attribute_invalid_on_stmt)\n";
OS << " << AL << St->getBeginLoc();\n";
OS << " << AL << AL.isRegularKeywordAttribute() << "
"St->getBeginLoc();\n";
OS << " return false;\n";
OS << "}\n\n";
}
Expand All @@ -3918,7 +3947,7 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
OS << (Warn ? "warn_attribute_wrong_decl_type_str"
: "err_attribute_wrong_decl_type_str");
OS << ")\n";
OS << " << Attr << ";
OS << " << Attr << Attr.isRegularKeywordAttribute() << ";
OS << CalculateDiagnostic(*SubjectObj) << ";\n";
OS << " return false;\n";
OS << " }\n";
Expand Down Expand Up @@ -3989,7 +4018,8 @@ static void GenerateMutualExclusionsChecks(const Record &Attr,
for (const std::string &A : DeclAttrs) {
OS << " if (const auto *A = D->getAttr<" << A << ">()) {\n";
OS << " S.Diag(AL.getLoc(), diag::err_attributes_are_not_compatible)"
<< " << AL << A;\n";
<< " << AL << A << (AL.isRegularKeywordAttribute() ||"
<< " A->isRegularKeywordAttribute());\n";
OS << " S.Diag(A->getLocation(), diag::note_conflicting_attribute);";
OS << " \nreturn false;\n";
OS << " }\n";
Expand All @@ -4010,7 +4040,8 @@ static void GenerateMutualExclusionsChecks(const Record &Attr,
<< ">()) {\n";
MergeDeclOS << " S.Diag(First->getLocation(), "
<< "diag::err_attributes_are_not_compatible) << First << "
<< "Second;\n";
<< "Second << (First->isRegularKeywordAttribute() || "
<< "Second->isRegularKeywordAttribute());\n";
MergeDeclOS << " S.Diag(Second->getLocation(), "
<< "diag::note_conflicting_attribute);\n";
MergeDeclOS << " return false;\n";
Expand Down Expand Up @@ -4050,7 +4081,8 @@ static void GenerateMutualExclusionsChecks(const Record &Attr,
MergeStmtOS << " if (Iter != C.end()) {\n";
MergeStmtOS << " S.Diag((*Iter)->getLocation(), "
<< "diag::err_attributes_are_not_compatible) << *Iter << "
<< "Second;\n";
<< "Second << ((*Iter)->isRegularKeywordAttribute() || "
<< "Second->isRegularKeywordAttribute());\n";
MergeStmtOS << " S.Diag(Second->getLocation(), "
<< "diag::note_conflicting_attribute);\n";
MergeStmtOS << " return false;\n";
Expand Down
6 changes: 6 additions & 0 deletions clang/utils/TableGen/TableGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,6 +35,7 @@ enum ActionType {
GenClangAttrSubjectMatchRuleList,
GenClangAttrPCHRead,
GenClangAttrPCHWrite,
GenClangAttrTokenKinds,
GenClangAttrHasAttributeImpl,
GenClangAttrSpellingListIndex,
GenClangAttrASTVisitor,
Expand Down Expand Up @@ -135,6 +136,8 @@ cl::opt<ActionType> Action(
"Generate clang PCH attribute reader"),
clEnumValN(GenClangAttrPCHWrite, "gen-clang-attr-pch-write",
"Generate clang PCH attribute writer"),
clEnumValN(GenClangAttrTokenKinds, "gen-clang-attr-token-kinds",
"Generate a list of attribute-related clang tokens"),
clEnumValN(GenClangAttrHasAttributeImpl,
"gen-clang-attr-has-attribute-impl",
"Generate a clang attribute spelling list"),
Expand Down Expand Up @@ -324,6 +327,9 @@ bool ClangTableGenMain(raw_ostream &OS, RecordKeeper &Records) {
case GenClangAttrPCHWrite:
EmitClangAttrPCHWrite(Records, OS);
break;
case GenClangAttrTokenKinds:
EmitClangAttrTokenKinds(Records, OS);
break;
case GenClangAttrHasAttributeImpl:
EmitClangAttrHasAttrImpl(Records, OS);
break;
Expand Down
2 changes: 2 additions & 0 deletions clang/utils/TableGen/TableGenBackends.h
Original file line number Diff line number Diff line change
Expand Up @@ -43,6 +43,8 @@ void EmitClangAttrSubjectMatchRuleList(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangAttrPCHRead(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangAttrPCHWrite(llvm::RecordKeeper &Records, llvm::raw_ostream &OS);
void EmitClangAttrTokenKinds(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangAttrHasAttrImpl(llvm::RecordKeeper &Records,
llvm::raw_ostream &OS);
void EmitClangAttrSpellingListIndex(llvm::RecordKeeper &Records,
Expand Down