[clang-tools-extra] [clang] [llvm] [clang] Differentiate between identifier and string EnumArgument (PR #68550)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jan 12 23:36:53 PST 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: Sergei Barannikov (s-barannikov)
<details>
<summary>Changes</summary>
EnumArgument may be a string or an identifier. If it is a string, it should be parsed as unevaluated string literal. Add IsString flag to EnumArgument so that the parser can choose the correct parsing method.
Target-specific attributes that share spelling may have different attribute "prototypes". For example, ARM's version of "interrupt" attribute accepts a string enum, while MSP430's version accepts an unsigned integer. Adjust ClangAttrEmitter so that the generated `attributeStringLiteralListArg` returns the correct mask depending on target triple.
It is worth noting that even after this change some string arguments are still parsed as identifiers or, worse, as expressions. This is because of some special logic in `ParseAttributeArgsCommon`. Fixing it is out of scope of this patch.
---
Patch is 32.07 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/68550.diff
11 Files Affected:
- (modified) clang/include/clang/Basic/Attr.td (+48-36)
- (modified) clang/lib/Parse/ParseDecl.cpp (+2-2)
- (modified) clang/test/Sema/attr-function-return.c (+1-1)
- (modified) clang/test/Sema/callingconv-iamcu.c (+1-1)
- (modified) clang/test/Sema/callingconv.c (+1-1)
- (modified) clang/test/Sema/mips-interrupt-attr.c (+1)
- (modified) clang/test/Sema/riscv-interrupt-attr.c (+1)
- (modified) clang/test/Sema/zero_call_used_regs.c (+1-1)
- (modified) clang/test/SemaCXX/warn-consumed-parsing.cpp (+1-1)
- (modified) clang/test/SemaHLSL/shader_type_attr.hlsl (+2-2)
- (modified) clang/utils/TableGen/ClangAttrEmitter.cpp (+63-17)
``````````diff
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index a03b0e44e15f7d..6df1f3ba1a822f 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -284,12 +284,15 @@ class DefaultIntArgument<string name, int default> : IntArgument<name, 1> {
// 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<string name, string type, list<string> values,
+// possible values, and a list of enumerators to map them to.
+class EnumArgument<string name, string type, bit is_string, list<string> values,
list<string> enums, bit opt = 0, bit fake = 0,
bit isExternalType = 0>
: Argument<name, opt, fake> {
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<string> Values = values;
list<string> Enums = enums;
bit IsExternalType = isExternalType;
@@ -297,10 +300,14 @@ class EnumArgument<string name, string type, list<string> values,
// FIXME: There should be a VariadicArgument type that takes any other type
// of argument and generates the appropriate type.
-class VariadicEnumArgument<string name, string type, list<string> values,
- list<string> enums, bit isExternalType = 0>
+class VariadicEnumArgument<string name, string type, bit is_string,
+ list<string> values, list<string> enums,
+ bit isExternalType = 0>
: Argument<name, 1> {
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<string> Values = values;
list<string> Enums = enums;
bit IsExternalType = isExternalType;
@@ -904,7 +911,7 @@ def ARMInterrupt : InheritableAttr, TargetSpecificAttr<TargetARM> {
// 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>];
@@ -1029,7 +1036,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];
}
@@ -1611,7 +1619,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];
}
@@ -1777,7 +1785,7 @@ def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips32> {
// 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", ""],
@@ -1965,7 +1973,7 @@ def NoMicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> {
def RISCVInterrupt : InheritableAttr, TargetSpecificAttr<TargetRISCV> {
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>];
@@ -2336,7 +2344,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"]>];
@@ -2510,7 +2518,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];
@@ -2619,7 +2627,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"]>
];
@@ -2635,7 +2643,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];
@@ -2746,7 +2754,7 @@ def PragmaClangTextSection : InheritableAttr {
def CodeModel : InheritableAttr, TargetSpecificAttr<TargetLoongArch> {
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>;
@@ -2802,7 +2810,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>];
@@ -2812,7 +2820,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>];
@@ -2850,7 +2858,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",
@@ -3016,7 +3024,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",
@@ -3036,8 +3044,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>,
@@ -3139,7 +3147,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;
@@ -3149,7 +3157,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 = [Tag, ObjCInterface, Namespace];
@@ -3547,7 +3555,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];
@@ -3580,6 +3588,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];
@@ -3591,7 +3600,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];
@@ -3603,7 +3612,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];
@@ -3615,7 +3624,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];
@@ -3627,7 +3636,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];
@@ -3704,7 +3713,8 @@ def CFGuard : InheritableAttr, TargetSpecificAttr<TargetWindows> {
// 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];
}
@@ -3860,7 +3870,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",
@@ -3869,7 +3879,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",
@@ -3958,7 +3968,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">,
@@ -3978,10 +3988,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">,
@@ -4003,7 +4013,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",
@@ -4252,7 +4262,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"],
@@ -4268,10 +4278,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",
@@ -4328,7 +4340,7 @@ def : MutualExclusions<[RandomizeLayout, NoRandomizeLayout]>;
def FunctionReturnThunks : InheritableAttr,
TargetSpecificAttr<TargetAnyX86> {
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 ed684c5d57b1ee..e069e4350ff70e 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<uint32_t>(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 c6fe88b821e35f..d2c9156da7ab61 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 at +1 {{'function_return' attribute argument not supported: invalid}}
__attribute__((function_return("invalid"))) void v(void) {}
-// expected-error at +1 {{'function_return' attribute requires a string}}
+// expected-error at +1 {{expected string literal as argument of 'function_return' attribute}}
__attribute__((function_return(5))) void a(void) {}
// expected-error at +1 {{'function_return' attribute takes one argument}}
diff --git a/clang/test/Sema/callingconv-iamcu.c b/clang/test/Sema/callingconv-iamcu.c
index 2874a8164545aa..d6b8f8f011d0f3 100644
--- a/clang/test/Sema/callingconv-iamcu.c
+++ b/clang/test/Sema/callingconv-...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/68550
More information about the cfe-commits
mailing list