diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index 7e643b89971c1..fa191c7378dba 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -284,12 +284,15 @@ class DefaultIntArgument : IntArgument { // This argument is more complex, it includes the enumerator type // name, whether the enum type is externally defined, a list of -// strings to accept, and a list of enumerators to map them to. -class EnumArgument values, +// possible values, and a list of enumerators to map them to. +class EnumArgument values, list enums, bit opt = 0, bit fake = 0, bit isExternalType = 0> : Argument { string Type = type; + // When true, the argument will be parsed as an unevaluated string literal + // and otherwise as an identifier. + bit IsString = is_string; list Values = values; list Enums = enums; bit IsExternalType = isExternalType; @@ -297,10 +300,14 @@ class EnumArgument values, // FIXME: There should be a VariadicArgument type that takes any other type // of argument and generates the appropriate type. -class VariadicEnumArgument values, - list enums, bit isExternalType = 0> +class VariadicEnumArgument values, list enums, + bit isExternalType = 0> : Argument { string Type = type; + // When true, the argument will be parsed as an unevaluated string literal + // and otherwise as an identifier. + bit IsString = is_string; list Values = values; list Enums = enums; bit IsExternalType = isExternalType; @@ -907,7 +914,7 @@ def ARMInterrupt : InheritableAttr, TargetSpecificAttr { // MSP430Interrupt's, MipsInterrupt's and AnyX86Interrupt's spellings // must match. let Spellings = [GCC<"interrupt">]; - let Args = [EnumArgument<"Interrupt", "InterruptType", + let Args = [EnumArgument<"Interrupt", "InterruptType", /*is_string=*/true, ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", ""], ["IRQ", "FIQ", "SWI", "ABORT", "UNDEF", "Generic"], 1>]; @@ -1032,7 +1039,8 @@ def ExternalSourceSymbol : InheritableAttr { def Blocks : InheritableAttr { let Spellings = [Clang<"blocks">]; - let Args = [EnumArgument<"Type", "BlockType", ["byref"], ["ByRef"]>]; + let Args = [EnumArgument<"Type", "BlockType", /*is_string=*/true, + ["byref"], ["ByRef"]>]; let Documentation = [Undocumented]; } @@ -1614,7 +1622,7 @@ def FlagEnum : InheritableAttr { def EnumExtensibility : InheritableAttr { let Spellings = [Clang<"enum_extensibility">]; let Subjects = SubjectList<[Enum]>; - let Args = [EnumArgument<"Extensibility", "Kind", + let Args = [EnumArgument<"Extensibility", "Kind", /*is_string=*/false, ["closed", "open"], ["Closed", "Open"]>]; let Documentation = [EnumExtensibilityDocs]; } @@ -1780,7 +1788,7 @@ def MipsInterrupt : InheritableAttr, TargetSpecificAttr { // must match. let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[Function]>; - let Args = [EnumArgument<"Interrupt", "InterruptType", + let Args = [EnumArgument<"Interrupt", "InterruptType", /*is_string=*/true, ["vector=sw0", "vector=sw1", "vector=hw0", "vector=hw1", "vector=hw2", "vector=hw3", "vector=hw4", "vector=hw5", "eic", ""], @@ -1968,7 +1976,7 @@ def NoMicroMips : InheritableAttr, TargetSpecificAttr { def RISCVInterrupt : InheritableAttr, TargetSpecificAttr { let Spellings = [GCC<"interrupt">]; let Subjects = SubjectList<[Function]>; - let Args = [EnumArgument<"Interrupt", "InterruptType", + let Args = [EnumArgument<"Interrupt", "InterruptType", /*is_string=*/true, ["supervisor", "machine"], ["supervisor", "machine"], 1>]; @@ -2339,7 +2347,7 @@ def ObjCException : InheritableAttr { def ObjCMethodFamily : InheritableAttr { let Spellings = [Clang<"objc_method_family">]; let Subjects = SubjectList<[ObjCMethod], ErrorDiag>; - let Args = [EnumArgument<"Family", "FamilyKind", + let Args = [EnumArgument<"Family", "FamilyKind", /*is_string=*/false, ["none", "alloc", "copy", "init", "mutableCopy", "new"], ["OMF_None", "OMF_alloc", "OMF_copy", "OMF_init", "OMF_mutableCopy", "OMF_new"]>]; @@ -2513,7 +2521,7 @@ def IntelOclBicc : DeclOrTypeAttr { def Pcs : DeclOrTypeAttr { let Spellings = [GCC<"pcs">]; - let Args = [EnumArgument<"PCS", "PCSType", + let Args = [EnumArgument<"PCS", "PCSType", /*is_string=*/true, ["aapcs", "aapcs-vfp"], ["AAPCS", "AAPCS_VFP"]>]; // let Subjects = [Function, ObjCMethod]; @@ -2646,7 +2654,7 @@ def SwiftObjCMembers : Attr { def SwiftError : InheritableAttr { let Spellings = [GNU<"swift_error">]; let Args = [ - EnumArgument<"Convention", "ConventionKind", + EnumArgument<"Convention", "ConventionKind", /*is_string=*/false, ["none", "nonnull_error", "null_result", "zero_result", "nonzero_result"], ["None", "NonNullError", "NullResult", "ZeroResult", "NonZeroResult"]> ]; @@ -2678,7 +2686,7 @@ def SwiftName : InheritableAttr { def SwiftNewType : InheritableAttr { let Spellings = [GNU<"swift_newtype">, GNU<"swift_wrapper">]; - let Args = [EnumArgument<"NewtypeKind", "NewtypeKind", + let Args = [EnumArgument<"NewtypeKind", "NewtypeKind", /*is_string=*/false, ["struct", "enum"], ["NK_Struct", "NK_Enum"]>]; let Subjects = SubjectList<[TypedefName], ErrorDiag>; let Documentation = [SwiftNewTypeDocs]; @@ -2814,7 +2822,7 @@ def PragmaClangTextSection : InheritableAttr { def CodeModel : InheritableAttr, TargetSpecificAttr { let Spellings = [GCC<"model">]; - let Args = [EnumArgument<"Model", "llvm::CodeModel::Model", + let Args = [EnumArgument<"Model", "llvm::CodeModel::Model", /*is_string=*/1, ["normal", "medium", "extreme"], ["Small", "Medium", "Large"], /*opt=*/0, /*fake=*/0, /*isExternalType=*/1>]; let Subjects = SubjectList<[NonTLSGlobalVar], ErrorDiag>; @@ -2870,7 +2878,7 @@ def SwiftIndirectResult : ParameterABIAttr { def SwiftAsync : InheritableAttr { let Spellings = [Clang<"swift_async">]; let Subjects = SubjectList<[Function, ObjCMethod]>; - let Args = [EnumArgument<"Kind", "Kind", + let Args = [EnumArgument<"Kind", "Kind", /*is_string=*/false, ["none", "swift_private", "not_swift_private"], ["None", "SwiftPrivate", "NotSwiftPrivate"]>, ParamIdxArgument<"CompletionHandlerIndex", /*opt=*/1>]; @@ -2880,7 +2888,7 @@ def SwiftAsync : InheritableAttr { def SwiftAsyncError : InheritableAttr { let Spellings = [Clang<"swift_async_error">]; let Subjects = SubjectList<[Function, ObjCMethod]>; - let Args = [EnumArgument<"Convention", "ConventionKind", + let Args = [EnumArgument<"Convention", "ConventionKind", /*is_string=*/false, ["none", "nonnull_error", "zero_argument", "nonzero_argument"], ["None", "NonNullError", "ZeroArgument", "NonZeroArgument"]>, UnsignedArgument<"HandlerParamIdx", /*opt=*/1>]; @@ -2925,7 +2933,7 @@ def ZeroCallUsedRegs : InheritableAttr { let Spellings = [GCC<"zero_call_used_regs">]; let Subjects = SubjectList<[Function], ErrorDiag>; let Args = [ - EnumArgument<"ZeroCallUsedRegs", "ZeroCallUsedRegsKind", + EnumArgument<"ZeroCallUsedRegs", "ZeroCallUsedRegsKind", /*is_string=*/true, ["skip", "used-gpr-arg", "used-gpr", "used-arg", "used", "all-gpr-arg", "all-gpr", "all-arg", "all"], ["Skip", "UsedGPRArg", "UsedGPR", "UsedArg", "Used", @@ -3097,7 +3105,7 @@ def TransparentUnion : InheritableAttr { def Unavailable : InheritableAttr { let Spellings = [Clang<"unavailable">]; let Args = [StringArgument<"Message", 1>, - EnumArgument<"ImplicitReason", "ImplicitReason", + EnumArgument<"ImplicitReason", "ImplicitReason", /*is_string=*/0, // FIXME ["", "", "", ""], ["IR_None", "IR_ARCForbiddenType", @@ -3117,8 +3125,8 @@ def DiagnoseIf : InheritableAttr { let Spellings = [GNU<"diagnose_if">]; let Subjects = SubjectList<[Function, ObjCMethod, ObjCProperty]>; let Args = [ExprArgument<"Cond">, StringArgument<"Message">, - EnumArgument<"DiagnosticType", - "DiagnosticType", + EnumArgument<"DiagnosticType", "DiagnosticType", + /*is_string=*/true, ["error", "warning"], ["DT_Error", "DT_Warning"]>, BoolArgument<"ArgDependent", 0, /*fake*/ 1>, @@ -3220,7 +3228,7 @@ def MatrixType : TypeAttr { def Visibility : InheritableAttr { let Clone = 0; let Spellings = [GCC<"visibility">]; - let Args = [EnumArgument<"Visibility", "VisibilityType", + let Args = [EnumArgument<"Visibility", "VisibilityType", /*is_string=*/true, ["default", "hidden", "internal", "protected"], ["Default", "Hidden", "Hidden", "Protected"]>]; let MeaningfulToClassTemplateDefinition = 1; @@ -3230,7 +3238,7 @@ def Visibility : InheritableAttr { def TypeVisibility : InheritableAttr { let Clone = 0; let Spellings = [Clang<"type_visibility">]; - let Args = [EnumArgument<"Visibility", "VisibilityType", + let Args = [EnumArgument<"Visibility", "VisibilityType", /*is_string=*/true, ["default", "hidden", "internal", "protected"], ["Default", "Hidden", "Hidden", "Protected"]>]; // let Subjects = SubjectList<[Tag, ObjCInterface, Namespace], ErrorDiag>; @@ -3628,7 +3636,7 @@ def Consumable : InheritableAttr { // FIXME: should this attribute have a CPlusPlus language option? let Spellings = [Clang<"consumable", 0>]; let Subjects = SubjectList<[CXXRecord]>; - let Args = [EnumArgument<"DefaultState", "ConsumedState", + let Args = [EnumArgument<"DefaultState", "ConsumedState", /*is_string=*/false, ["unknown", "consumed", "unconsumed"], ["Unknown", "Consumed", "Unconsumed"]>]; let Documentation = [ConsumableDocs]; @@ -3661,6 +3669,7 @@ def CallableWhen : InheritableAttr { let Spellings = [Clang<"callable_when", 0>]; let Subjects = SubjectList<[CXXMethod]>; let Args = [VariadicEnumArgument<"CallableStates", "ConsumedState", + /*is_string=*/true, ["unknown", "consumed", "unconsumed"], ["Unknown", "Consumed", "Unconsumed"]>]; let Documentation = [CallableWhenDocs]; @@ -3672,7 +3681,7 @@ def ParamTypestate : InheritableAttr { // FIXME: should this attribute have a CPlusPlus language option? let Spellings = [Clang<"param_typestate", 0>]; let Subjects = SubjectList<[ParmVar]>; - let Args = [EnumArgument<"ParamState", "ConsumedState", + let Args = [EnumArgument<"ParamState", "ConsumedState", /*is_string=*/false, ["unknown", "consumed", "unconsumed"], ["Unknown", "Consumed", "Unconsumed"]>]; let Documentation = [ParamTypestateDocs]; @@ -3684,7 +3693,7 @@ def ReturnTypestate : InheritableAttr { // FIXME: should this attribute have a CPlusPlus language option? let Spellings = [Clang<"return_typestate", 0>]; let Subjects = SubjectList<[Function, ParmVar]>; - let Args = [EnumArgument<"State", "ConsumedState", + let Args = [EnumArgument<"State", "ConsumedState", /*is_string=*/false, ["unknown", "consumed", "unconsumed"], ["Unknown", "Consumed", "Unconsumed"]>]; let Documentation = [ReturnTypestateDocs]; @@ -3696,7 +3705,7 @@ def SetTypestate : InheritableAttr { // FIXME: should this attribute have a CPlusPlus language option? let Spellings = [Clang<"set_typestate", 0>]; let Subjects = SubjectList<[CXXMethod]>; - let Args = [EnumArgument<"NewState", "ConsumedState", + let Args = [EnumArgument<"NewState", "ConsumedState", /*is_string=*/false, ["unknown", "consumed", "unconsumed"], ["Unknown", "Consumed", "Unconsumed"]>]; let Documentation = [SetTypestateDocs]; @@ -3708,7 +3717,7 @@ def TestTypestate : InheritableAttr { // FIXME: should this attribute have a CPlusPlus language option? let Spellings = [Clang<"test_typestate", 0>]; let Subjects = SubjectList<[CXXMethod]>; - let Args = [EnumArgument<"TestState", "ConsumedState", + let Args = [EnumArgument<"TestState", "ConsumedState", /*is_string=*/false, ["consumed", "unconsumed"], ["Consumed", "Unconsumed"]>]; let Documentation = [TestTypestateDocs]; @@ -3785,7 +3794,8 @@ def CFGuard : InheritableAttr, TargetSpecificAttr { // we might also want to support __declspec(guard(suppress)). let Spellings = [Declspec<"guard">, Clang<"guard">]; let Subjects = SubjectList<[Function]>; - let Args = [EnumArgument<"Guard", "GuardArg", ["nocf"], ["nocf"]>]; + let Args = [EnumArgument<"Guard", "GuardArg", /*is_string=*/false, + ["nocf"], ["nocf"]>]; let Documentation = [CFGuardDocs]; } @@ -3941,7 +3951,7 @@ def LoopHint : Attr { Pragma<"", "nounroll_and_jam">]; /// State of the loop optimization specified by the spelling. - let Args = [EnumArgument<"Option", "OptionType", + let Args = [EnumArgument<"Option", "OptionType", /*is_string=*/false, ["vectorize", "vectorize_width", "interleave", "interleave_count", "unroll", "unroll_count", "unroll_and_jam", "unroll_and_jam_count", "pipeline", "pipeline_initiation_interval", "distribute", @@ -3950,7 +3960,7 @@ def LoopHint : Attr { "Unroll", "UnrollCount", "UnrollAndJam", "UnrollAndJamCount", "PipelineDisabled", "PipelineInitiationInterval", "Distribute", "VectorizePredicate"]>, - EnumArgument<"State", "LoopHintState", + EnumArgument<"State", "LoopHintState", /*is_string=*/false, ["enable", "disable", "numeric", "fixed_width", "scalable_width", "assume_safety", "full"], ["Enable", "Disable", "Numeric", "FixedWidth", @@ -4039,7 +4049,7 @@ def OMPDeclareSimdDecl : Attr { let HasCustomParsing = 1; let Documentation = [OMPDeclareSimdDocs]; let Args = [ - EnumArgument<"BranchState", "BranchStateTy", + EnumArgument<"BranchState", "BranchStateTy", /*is_string=*/false, [ "", "inbranch", "notinbranch" ], [ "BS_Undefined", "BS_Inbranch", "BS_Notinbranch" ]>, ExprArgument<"Simdlen">, VariadicExprArgument<"Uniforms">, @@ -4059,10 +4069,10 @@ def OMPDeclareTargetDecl : InheritableAttr { let Subjects = SubjectList<[Function, SharedVar]>; let Documentation = [OMPDeclareTargetDocs]; let Args = [ - EnumArgument<"MapType", "MapTypeTy", + EnumArgument<"MapType", "MapTypeTy", /*is_string=*/false, [ "to", "enter", "link" ], [ "MT_To", "MT_Enter", "MT_Link" ]>, - EnumArgument<"DevType", "DevTypeTy", + EnumArgument<"DevType", "DevTypeTy", /*is_string=*/false, [ "host", "nohost", "any" ], [ "DT_Host", "DT_NoHost", "DT_Any" ]>, ExprArgument<"IndirectExpr">, @@ -4084,7 +4094,7 @@ def OMPAllocateDecl : InheritableAttr { let Spellings = []; let SemaHandler = 0; let Args = [ - EnumArgument<"AllocatorType", "AllocatorTypeTy", + EnumArgument<"AllocatorType", "AllocatorTypeTy", /*is_string=*/false, [ "omp_null_allocator", "omp_default_mem_alloc", "omp_large_cap_mem_alloc", "omp_const_mem_alloc", @@ -4333,7 +4343,7 @@ def HLSLShader : InheritableAttr { let Subjects = SubjectList<[HLSLEntry]>; let LangOpts = [HLSL]; let Args = [ - EnumArgument<"Type", "ShaderType", + EnumArgument<"Type", "ShaderType", /*is_string=*/true, ["pixel", "vertex", "geometry", "hull", "domain", "compute", "raygeneration", "intersection", "anyhit", "closesthit", "miss", "callable", "mesh", "amplification"], @@ -4349,10 +4359,12 @@ def HLSLResource : InheritableAttr { let Subjects = SubjectList<[Struct]>; let LangOpts = [HLSL]; let Args = [EnumArgument<"ResourceClass", "llvm::hlsl::ResourceClass", + /*is_string=*/0, ["SRV", "UAV", "CBuffer", "Sampler"], ["SRV", "UAV", "CBuffer", "Sampler"], /*opt=*/0, /*fake=*/0, /*isExternalType=*/1>, EnumArgument<"ResourceKind", "llvm::hlsl::ResourceKind", + /*is_string=*/0, ["Texture1D", "Texture2D", "Texture2DMS", "Texture3D", "TextureCube", "Texture1DArray", "Texture2DArray", "Texture2DMSArray", @@ -4409,7 +4421,7 @@ def : MutualExclusions<[RandomizeLayout, NoRandomizeLayout]>; def FunctionReturnThunks : InheritableAttr, TargetSpecificAttr { let Spellings = [GCC<"function_return">]; - let Args = [EnumArgument<"ThunkType", "Kind", + let Args = [EnumArgument<"ThunkType", "Kind", /*is_string=*/true, ["keep", "thunk-extern"], ["Keep", "Extern"] >]; diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp index 0728113ba7c93..edfab11c37cf0 100644 --- a/clang/lib/Parse/ParseDecl.cpp +++ b/clang/lib/Parse/ParseDecl.cpp @@ -291,7 +291,7 @@ static bool attributeHasIdentifierArg(const IdentifierInfo &II) { /// Determine whether the given attribute has an identifier argument. static ParsedAttributeArgumentsProperties -attributeStringLiteralListArg(const IdentifierInfo &II) { +attributeStringLiteralListArg(const llvm::Triple &T, const IdentifierInfo &II) { #define CLANG_ATTR_STRING_LITERAL_ARG_LIST return llvm::StringSwitch(normalizeAttrName(II.getName())) #include "clang/Parse/AttrParserStringSwitches.inc" @@ -550,7 +550,7 @@ unsigned Parser::ParseAttributeArgsCommon( ExprVector ParsedExprs; ParsedAttributeArgumentsProperties ArgProperties = - attributeStringLiteralListArg(*AttrName); + attributeStringLiteralListArg(getTargetInfo().getTriple(), *AttrName); if (ParseAttributeArgumentList(*AttrName, ParsedExprs, ArgProperties)) { SkipUntil(tok::r_paren, StopAtSemi); return 0; diff --git a/clang/test/Sema/attr-function-return.c b/clang/test/Sema/attr-function-return.c index c6fe88b821e35..d2c9156da7ab6 100644 --- a/clang/test/Sema/attr-function-return.c +++ b/clang/test/Sema/attr-function-return.c @@ -13,7 +13,7 @@ __attribute__((function_return("thunk-extern"))) void w(void) {} // expected-warning@+1 {{'function_return' attribute argument not supported: invalid}} __attribute__((function_return("invalid"))) void v(void) {} -// expected-error@+1 {{'function_return' attribute requires a string}} +// expected-error@+1 {{expected string literal as argument of 'function_return' attribute}} __attribute__((function_return(5))) void a(void) {} // expected-error@+1 {{'function_return' attribute takes one argument}} diff --git a/clang/test/Sema/callingconv-iamcu.c b/clang/test/Sema/callingconv-iamcu.c index 2874a8164545a..d6b8f8f011d0f 100644 --- a/clang/test/Sema/callingconv-iamcu.c +++ b/clang/test/Sema/callingconv-iamcu.c @@ -36,7 +36,7 @@ int __attribute__((pcs("aapcs", "aapcs"))) pcs1(void); // expected-error {{'pcs' int __attribute__((pcs())) pcs2(void); // expected-error {{'pcs' attribute takes one argument}} int __attribute__((pcs(pcs1))) pcs3(void); // expected-error {{'pcs' attribute requires a string}} \ // expected-error {{invalid PCS type}} -int __attribute__((pcs(0))) pcs4(void); // expected-error {{'pcs' attribute requires a string}} +int __attribute__((pcs(0))) pcs4(void); // expected-error {{expected string literal as argument of 'pcs' attribute}} /* These are ignored because the target is i386 and not ARM */ int __attribute__((pcs("aapcs"))) pcs5(void); // expected-warning {{'pcs' calling convention is not supported for this target}} int __attribute__((pcs("aapcs-vfp"))) pcs6(void); // expected-warning {{'pcs' calling convention is not supported for this target}} diff --git a/clang/test/Sema/callingconv.c b/clang/test/Sema/callingconv.c index fd009b8973bfc..f0b8b80a32974 100644 --- a/clang/test/Sema/callingconv.c +++ b/clang/test/Sema/callingconv.c @@ -45,7 +45,7 @@ int __attribute__((pcs("aapcs", "aapcs"))) pcs1(void); // expected-error {{'pcs' int __attribute__((pcs())) pcs2(void); // expected-error {{'pcs' attribute takes one argument}} int __attribute__((pcs(pcs1))) pcs3(void); // expected-error {{'pcs' attribute requires a string}} \ // expected-error {{invalid PCS type}} -int __attribute__((pcs(0))) pcs4(void); // expected-error {{'pcs' attribute requires a string}} +int __attribute__((pcs(0))) pcs4(void); // expected-error {{expected string literal as argument of 'pcs' attribute}} /* These are ignored because the target is i386 and not ARM */ int __attribute__((pcs("aapcs"))) pcs5(void); // expected-warning {{'pcs' calling convention is not supported for this target}} int __attribute__((pcs("aapcs-vfp"))) pcs6(void); // expected-warning {{'pcs' calling convention is not supported for this target}} diff --git a/clang/test/Sema/mips-interrupt-attr.c b/clang/test/Sema/mips-interrupt-attr.c index 7f8958341b8f0..733f899ecf239 100644 --- a/clang/test/Sema/mips-interrupt-attr.c +++ b/clang/test/Sema/mips-interrupt-attr.c @@ -3,6 +3,7 @@ struct a { int b; }; struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to functions and methods}} +__attribute((interrupt(42))) void foo0(void) {} // expected-error {{expected string literal as argument of 'interrupt' attribute}} __attribute__((interrupt("EIC"))) void foo1(void) {} // expected-warning {{'interrupt' attribute argument not supported: 'EIC'}} __attribute__((interrupt("eic", 1))) void foo2(void) {} // expected-error {{'interrupt' attribute takes no more than 1 argument}} diff --git a/clang/test/Sema/riscv-interrupt-attr.c b/clang/test/Sema/riscv-interrupt-attr.c index e66a5799bb394..756bfa0582de7 100644 --- a/clang/test/Sema/riscv-interrupt-attr.c +++ b/clang/test/Sema/riscv-interrupt-attr.c @@ -25,6 +25,7 @@ struct a { int b; }; struct a test __attribute__((interrupt)); // expected-warning {{'interrupt' attribute only applies to functions}} +__attribute__((interrupt(42))) void foo0(void) {} // expected-error {{expected string literal as argument of 'interrupt' attribute}} __attribute__((interrupt("USER"))) void foo1(void) {} // expected-warning {{'interrupt' attribute argument not supported: USER}} __attribute__((interrupt("user"))) void foo1b(void) {} // expected-warning {{'interrupt' attribute argument not supported: user}} __attribute__((interrupt("MACHINE"))) void foo1c(void) {} // expected-warning {{'interrupt' attribute argument not supported: MACHINE}} diff --git a/clang/test/Sema/zero_call_used_regs.c b/clang/test/Sema/zero_call_used_regs.c index 3313707f97cf9..6de18fa3d7d0d 100644 --- a/clang/test/Sema/zero_call_used_regs.c +++ b/clang/test/Sema/zero_call_used_regs.c @@ -4,7 +4,7 @@ void failure1(void) _zero_call_used_regs(); // expected-error {{takes one argument}} void failure2(void) _zero_call_used_regs("used", "used-gpr"); // expected-error {{takes one argument}} -void failure3(void) _zero_call_used_regs(0); // expected-error {{requires a string}} +void failure3(void) _zero_call_used_regs(0); // expected-error {{expected string literal}} void failure4(void) _zero_call_used_regs("hello"); // expected-warning {{argument not supported: hello}} void success1(void) _zero_call_used_regs("skip"); diff --git a/clang/test/SemaCXX/warn-consumed-parsing.cpp b/clang/test/SemaCXX/warn-consumed-parsing.cpp index 722a60bf98632..63f4135d0d265 100644 --- a/clang/test/SemaCXX/warn-consumed-parsing.cpp +++ b/clang/test/SemaCXX/warn-consumed-parsing.cpp @@ -35,7 +35,7 @@ void function3() CONSUMABLE(consumed); // expected-warning {{'consumable' attrib class CONSUMABLE(unknown) AttrTester1 { void callableWhen0() CALLABLE_WHEN("unconsumed"); - void callableWhen1() CALLABLE_WHEN(42); // expected-error {{'callable_when' attribute requires a string}} + void callableWhen1() CALLABLE_WHEN(42); // expected-error {{expected string literal as argument of 'callable_when' attribute}} void callableWhen2() CALLABLE_WHEN("foo"); // expected-warning {{'callable_when' attribute argument not supported: foo}} void callableWhen3() CALLABLE_WHEN(unconsumed); void consumes() SET_TYPESTATE(consumed); diff --git a/clang/test/SemaHLSL/shader_type_attr.hlsl b/clang/test/SemaHLSL/shader_type_attr.hlsl index d497b0582d1a7..52d3b1c9d012f 100644 --- a/clang/test/SemaHLSL/shader_type_attr.hlsl +++ b/clang/test/SemaHLSL/shader_type_attr.hlsl @@ -47,9 +47,9 @@ int forwardDecl() { // expected-error@+1 {{'shader' attribute takes one argument}} [shader()] -// expected-error@+1 {{'shader' attribute takes one argument}} +// expected-error@+1 {{expected string literal as argument of 'shader' attribute}} [shader(1, 2)] -// expected-error@+1 {{'shader' attribute requires a string}} +// expected-error@+1 {{expected string literal as argument of 'shader' attribute}} [shader(1)] // expected-warning@+1 {{'shader' attribute argument not supported: cs}} [shader("cs")] diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 89b88e386f257..935b9846990ee 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -171,12 +171,13 @@ static StringRef NormalizeGNUAttrSpelling(StringRef AttrSpelling) { typedef std::vector> ParsedAttrMap; static ParsedAttrMap getParsedAttrList(const RecordKeeper &Records, - ParsedAttrMap *Dupes = nullptr) { + ParsedAttrMap *Dupes = nullptr, + bool SemaOnly = true) { std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); std::set Seen; ParsedAttrMap R; for (const auto *Attr : Attrs) { - if (Attr->getValueAsBit("SemaHandler")) { + if (!SemaOnly || Attr->getValueAsBit("SemaHandler")) { std::string AN; if (Attr->isSubClassOf("TargetSpecificAttr") && !Attr->isValueUnset("ParseKind")) { @@ -2358,19 +2359,21 @@ static bool isVariadicExprArgument(const Record *Arg) { } static bool isStringLiteralArgument(const Record *Arg) { - return !Arg->getSuperClasses().empty() && - llvm::StringSwitch( - Arg->getSuperClasses().back().first->getName()) - .Case("StringArgument", true) - .Default(false); + if (Arg->getSuperClasses().empty()) + return false; + StringRef ArgKind = Arg->getSuperClasses().back().first->getName(); + if (ArgKind == "EnumArgument") + return Arg->getValueAsBit("IsString"); + return ArgKind == "StringArgument"; } static bool isVariadicStringLiteralArgument(const Record *Arg) { - return !Arg->getSuperClasses().empty() && - llvm::StringSwitch( - Arg->getSuperClasses().back().first->getName()) - .Case("VariadicStringArgument", true) - .Default(false); + if (Arg->getSuperClasses().empty()) + return false; + StringRef ArgKind = Arg->getSuperClasses().back().first->getName(); + if (ArgKind == "VariadicEnumArgument") + return Arg->getValueAsBit("IsString"); + return ArgKind == "VariadicStringArgument"; } static void emitClangAttrVariadicIdentifierArgList(RecordKeeper &Records, @@ -2393,14 +2396,18 @@ static void emitClangAttrVariadicIdentifierArgList(RecordKeeper &Records, OS << "#endif // CLANG_ATTR_VARIADIC_IDENTIFIER_ARG_LIST\n\n"; } +static bool GenerateTargetSpecificAttrChecks(const Record *R, + std::vector &Arches, + std::string &Test, + std::string *FnName); + // Emits the list of arguments that should be parsed as unevaluated string // literals for each attribute. static void emitClangAttrUnevaluatedStringLiteralList(RecordKeeper &Records, raw_ostream &OS) { OS << "#if defined(CLANG_ATTR_STRING_LITERAL_ARG_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); - for (const auto *Attr : Attrs) { - std::vector Args = Attr->getValueAsListOfDefs("Args"); + + auto MakeMask = [](ArrayRef Args) { uint32_t Bits = 0; assert(Args.size() <= 32 && "unsupported number of arguments in attribute"); for (uint32_t N = 0; N < Args.size(); ++N) { @@ -2411,11 +2418,46 @@ static void emitClangAttrUnevaluatedStringLiteralList(RecordKeeper &Records, break; } } - if (!Bits) + return Bits; + }; + + auto AddMaskWithTargetCheck = [](const Record *Attr, uint32_t Mask, + std::string &MaskStr) { + const Record *T = Attr->getValueAsDef("Target"); + std::vector Arches = T->getValueAsListOfStrings("Arches"); + std::string Test; + GenerateTargetSpecificAttrChecks(T, Arches, Test, nullptr); + MaskStr.append(Test + " ? " + std::to_string(Mask) + " : "); + }; + + ParsedAttrMap Dupes; + ParsedAttrMap Attrs = getParsedAttrList(Records, &Dupes, /*SemaOnly=*/false); + for (const auto &[AttrName, Attr] : Attrs) { + std::string MaskStr; + if (Attr->isSubClassOf("TargetSpecificAttr") && + !Attr->isValueUnset("ParseKind")) { + if (uint32_t Mask = MakeMask(Attr->getValueAsListOfDefs("Args"))) + AddMaskWithTargetCheck(Attr, Mask, MaskStr); + StringRef ParseKind = Attr->getValueAsString("ParseKind"); + for (const auto &[DupeParseKind, DupAttr] : Dupes) { + if (DupeParseKind != ParseKind) + continue; + if (uint32_t Mask = MakeMask(DupAttr->getValueAsListOfDefs("Args"))) + AddMaskWithTargetCheck(DupAttr, Mask, MaskStr); + } + if (!MaskStr.empty()) + MaskStr.append("0"); + } else { + if (uint32_t Mask = MakeMask(Attr->getValueAsListOfDefs("Args"))) + MaskStr = std::to_string(Mask); + } + + if (MaskStr.empty()) continue; + // All these spellings have at least one string literal has argument. forEachUniqueSpelling(*Attr, [&](const FlattenedSpelling &S) { - OS << ".Case(\"" << S.name() << "\", " << Bits << ")\n"; + OS << ".Case(\"" << S.name() << "\", " << MaskStr << ")\n"; }); } OS << "#endif // CLANG_ATTR_STRING_LITERAL_ARG_LIST\n\n"; @@ -3404,6 +3446,8 @@ void EmitClangAttrPCHWrite(RecordKeeper &Records, raw_ostream &OS) { OS << " }\n"; } +} // namespace clang + // Helper function for GenerateTargetSpecificAttrChecks that alters the 'Test' // parameter with only a single check type, if applicable. static bool GenerateTargetSpecificAttrCheck(const Record *R, std::string &Test, @@ -3570,6 +3614,8 @@ static void GenerateHasAttrSpellingStringSwitch( OS << " .Default(0);\n"; } +namespace clang { + // Emits list of regular keyword attributes with info about their arguments. void EmitClangRegularKeywordAttributeInfo(RecordKeeper &Records, raw_ostream &OS) {