Add a new attribute meta-spelling called "GCC" -- it widens into being a GNU spelling, and a CXX11 spelling with the namespace "gnu". It also sets a bit on the spelling certifying that it is known to GCC. From this, we can warn about the extension appropriately. As a consequence, the FunctionDefinition functionality is completely removed.

Replacing the functionality from r199676, which didn't solve the problem as elegantly.

llvm-svn: 200252
This commit is contained in:
Aaron Ballman 2014-01-27 22:10:04 +00:00
parent 340e44074b
commit c669cc0d77
6 changed files with 208 additions and 195 deletions

View File

@ -74,12 +74,6 @@ def HasFunctionProto : SubsetSubject<DeclBase,
isa<ObjCMethodDecl>(S) ||
isa<BlockDecl>(S)}]>;
// This is a fake Decl node that represents a function definition as well as a
// function declaration. This can be used for attributes which are allowed to
// appear on the definition of a function that's been late parsed. It is
// treated and diagnosed the same as a FunctionDecl.
def FunctionDefinition : DDecl<Function, 1>;
// A single argument to an attribute
class Argument<string name, bit optional> {
string Name = name;
@ -132,6 +126,7 @@ class VariadicEnumArgument<string name, string type, list<string> values,
class Spelling<string name, string variety> {
string Name = name;
string Variety = variety;
bit KnownToGCC;
}
class GNU<string name> : Spelling<name, "GNU">;
@ -141,6 +136,13 @@ class CXX11<string namespace, string name> : Spelling<name, "CXX11"> {
}
class Keyword<string name> : Spelling<name, "Keyword">;
// The GCC spelling implies GNU<name, "GNU"> and CXX11<"gnu", name> and also
// sets KnownToGCC to 1. This spelling should be used for any GCC-compatible
// attributes.
class GCC<string name> : Spelling<name, "GCC"> {
let KnownToGCC = 1;
}
class Accessor<string name, list<Spelling> spellings> {
string Name = name;
list<Spelling> Spellings = spellings;
@ -270,16 +272,16 @@ def AddressSpace : TypeAttr {
}
def Alias : Attr {
let Spellings = [GNU<"alias">, CXX11<"gnu", "alias">];
let Spellings = [GCC<"alias">];
let Args = [StringArgument<"Aliasee">];
}
def Aligned : InheritableAttr {
let Spellings = [GNU<"aligned">, Declspec<"align">, CXX11<"gnu", "aligned">,
Keyword<"alignas">, Keyword<"_Alignas">];
let Spellings = [GCC<"aligned">, Declspec<"align">, Keyword<"alignas">,
Keyword<"_Alignas">];
// let Subjects = SubjectList<[NonBitField, NormalVar, Tag]>;
let Args = [AlignedArgument<"Alignment", 1>];
let Accessors = [Accessor<"isGNU", [GNU<"aligned">, CXX11<"gnu","aligned">]>,
let Accessors = [Accessor<"isGNU", [GCC<"aligned">]>,
Accessor<"isC11", [Keyword<"_Alignas">]>,
Accessor<"isAlignas", [Keyword<"alignas">,
Keyword<"_Alignas">]>,
@ -293,12 +295,12 @@ def AlignMac68k : InheritableAttr {
}
def AlwaysInline : InheritableAttr {
let Spellings = [GNU<"always_inline">, CXX11<"gnu", "always_inline">];
let Spellings = [GCC<"always_inline">];
let Subjects = SubjectList<[Function]>;
}
def TLSModel : InheritableAttr {
let Spellings = [GNU<"tls_model">, CXX11<"gnu", "tls_model">];
let Spellings = [GCC<"tls_model">];
let Subjects = SubjectList<[TLSVar], ErrorDiag, "ExpectedTLSVar">;
let Args = [StringArgument<"Model">];
}
@ -363,8 +365,7 @@ def CarriesDependency : InheritableParamAttr {
}
def CDecl : InheritableAttr {
let Spellings = [GNU<"cdecl">, CXX11<"gnu", "cdecl">, Keyword<"__cdecl">,
Keyword<"_cdecl">];
let Spellings = [GCC<"cdecl">, Keyword<"__cdecl">, Keyword<"_cdecl">];
// let Subjects = [Function, ObjCMethod];
}
@ -401,28 +402,27 @@ def CFConsumed : InheritableParamAttr {
}
def Cleanup : InheritableAttr {
let Spellings = [GNU<"cleanup">, CXX11<"gnu", "cleanup">];
let Spellings = [GCC<"cleanup">];
let Args = [FunctionArgument<"FunctionDecl">];
let Subjects = SubjectList<[Var]>;
}
def Cold : InheritableAttr {
let Spellings = [GNU<"cold">, CXX11<"gnu", "cold">];
let Spellings = [GCC<"cold">];
let Subjects = SubjectList<[Function]>;
}
def Common : InheritableAttr {
let Spellings = [GNU<"common">, CXX11<"gnu", "common">];
let Spellings = [GCC<"common">];
let Subjects = SubjectList<[Var]>;
}
def Const : InheritableAttr {
let Spellings = [GNU<"const">, GNU<"__const">,
CXX11<"gnu", "const">, CXX11<"gnu", "__const">];
let Spellings = [GCC<"const">, GCC<"__const">];
}
def Constructor : InheritableAttr {
let Spellings = [GNU<"constructor">, CXX11<"gnu", "constructor">];
let Spellings = [GCC<"constructor">];
let Args = [DefaultIntArgument<"Priority", 65535>];
let Subjects = SubjectList<[Function]>;
}
@ -516,20 +516,20 @@ def OpenCLConstantAddressSpace : TypeAttr {
}
def Deprecated : InheritableAttr {
let Spellings = [GNU<"deprecated">, Declspec<"deprecated">,
CXX11<"gnu", "deprecated">, CXX11<"","deprecated">];
let Spellings = [GCC<"deprecated">, Declspec<"deprecated">,
CXX11<"","deprecated">];
let Args = [StringArgument<"Message", 1>];
}
def Destructor : InheritableAttr {
let Spellings = [GNU<"destructor">, CXX11<"gnu", "destructor">];
let Spellings = [GCC<"destructor">];
let Args = [DefaultIntArgument<"Priority", 65535>];
let Subjects = SubjectList<[Function]>;
}
def EnableIf : InheritableAttr {
let Spellings = [GNU<"enable_if">];
let Subjects = SubjectList<[FunctionDefinition]>;
let Subjects = SubjectList<[Function]>;
let Args = [ExprArgument<"Cond">, StringArgument<"Message">];
let TemplateDependent = 1;
}
@ -547,8 +547,8 @@ def FallThrough : Attr {
}
def FastCall : InheritableAttr {
let Spellings = [GNU<"fastcall">, CXX11<"gnu", "fastcall">,
Keyword<"__fastcall">, Keyword<"_fastcall">];
let Spellings = [GCC<"fastcall">, Keyword<"__fastcall">,
Keyword<"_fastcall">];
// let Subjects = [Function, ObjCMethod];
}
@ -564,7 +564,7 @@ def MinSize : InheritableAttr {
}
def Format : InheritableAttr {
let Spellings = [GNU<"format">, CXX11<"gnu", "format">];
let Spellings = [GCC<"format">];
let Args = [IdentifierArgument<"Type">, IntArgument<"FormatIdx">,
IntArgument<"FirstArg">];
let Subjects = SubjectList<[ObjCMethod, Block, HasFunctionProto], WarnDiag,
@ -572,19 +572,19 @@ def Format : InheritableAttr {
}
def FormatArg : InheritableAttr {
let Spellings = [GNU<"format_arg">, CXX11<"gnu", "format_arg">];
let Spellings = [GCC<"format_arg">];
let Args = [IntArgument<"FormatIdx">];
let Subjects = SubjectList<[ObjCMethod, HasFunctionProto], WarnDiag,
"ExpectedFunction">;
}
def GNUInline : InheritableAttr {
let Spellings = [GNU<"gnu_inline">, CXX11<"gnu", "gnu_inline">];
let Spellings = [GCC<"gnu_inline">];
let Subjects = SubjectList<[Function]>;
}
def Hot : InheritableAttr {
let Spellings = [GNU<"hot">, CXX11<"gnu", "hot">];
let Spellings = [GCC<"hot">];
let Subjects = SubjectList<[Function]>;
// An AST node is created for this attribute, but not actually used beyond
// semantic checking for mutual exclusion with the Cold attribute.
@ -611,7 +611,7 @@ def IBOutletCollection : InheritableAttr {
}
def Malloc : InheritableAttr {
let Spellings = [GNU<"malloc">, CXX11<"gnu", "malloc">];
let Spellings = [GCC<"malloc">];
// let Subjects = [Function];
}
@ -623,11 +623,12 @@ def MaxFieldAlignment : InheritableAttr {
}
def MayAlias : InheritableAttr {
let Spellings = [GNU<"may_alias">, CXX11<"gnu", "may_alias">];
// FIXME: this is a type attribute in GCC, but a declaration attribute here.
let Spellings = [GCC<"may_alias">];
}
def MSABI : InheritableAttr {
let Spellings = [GNU<"ms_abi">, CXX11<"gnu", "ms_abi">];
let Spellings = [GCC<"ms_abi">];
// let Subjects = [Function, ObjCMethod];
}
@ -641,17 +642,17 @@ def MSP430Interrupt : InheritableAttr, TargetSpecificAttr<TargetMSP430> {
}
def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
let Spellings = [GNU<"mips16">, CXX11<"gnu", "mips16">];
let Spellings = [GCC<"mips16">];
let Subjects = SubjectList<[Function], ErrorDiag>;
}
def Mode : Attr {
let Spellings = [GNU<"mode">, CXX11<"gnu", "mode">];
let Spellings = [GCC<"mode">];
let Args = [IdentifierArgument<"Mode">];
}
def Naked : InheritableAttr {
let Spellings = [GNU<"naked">, CXX11<"gnu", "naked">, Declspec<"naked">];
let Spellings = [GCC<"naked">, Declspec<"naked">];
let Subjects = SubjectList<[Function]>;
}
@ -666,12 +667,12 @@ def NeonVectorType : TypeAttr {
}
def ReturnsTwice : InheritableAttr {
let Spellings = [GNU<"returns_twice">, CXX11<"gnu", "returns_twice">];
let Spellings = [GCC<"returns_twice">];
let Subjects = SubjectList<[Function]>;
}
def NoCommon : InheritableAttr {
let Spellings = [GNU<"nocommon">, CXX11<"gnu", "nocommon">];
let Spellings = [GCC<"nocommon">];
let Subjects = SubjectList<[Var]>;
}
@ -680,18 +681,17 @@ def NoDebug : InheritableAttr {
}
def NoInline : InheritableAttr {
let Spellings = [GNU<"noinline">, CXX11<"gnu", "noinline">,
Declspec<"noinline">];
let Spellings = [GCC<"noinline">, Declspec<"noinline">];
let Subjects = SubjectList<[Function]>;
}
def NoMips16 : InheritableAttr, TargetSpecificAttr<TargetMips> {
let Spellings = [GNU<"nomips16">, CXX11<"gnu", "nomips16">];
let Spellings = [GCC<"nomips16">];
let Subjects = SubjectList<[Function], ErrorDiag>;
}
def NonNull : InheritableAttr {
let Spellings = [GNU<"nonnull">, CXX11<"gnu", "nonnull">];
let Spellings = [GCC<"nonnull">];
let Subjects = SubjectList<[ObjCMethod, HasFunctionProto, ParmVar], WarnDiag,
"ExpectedFunctionMethodOrParameter">;
let Args = [VariadicUnsignedArgument<"Args">];
@ -706,26 +706,23 @@ def NonNull : InheritableAttr {
}
def ReturnsNonNull : InheritableAttr {
let Spellings = [GNU<"returns_nonnull">, CXX11<"gnu", "returns_nonnull">];
let Spellings = [GCC<"returns_nonnull">];
let Subjects = SubjectList<[ObjCMethod, HasFunctionProto], WarnDiag,
"ExpectedFunctionOrMethod">;
}
def NoReturn : InheritableAttr {
let Spellings = [GNU<"noreturn">, CXX11<"gnu", "noreturn">,
Declspec<"noreturn">];
let Spellings = [GCC<"noreturn">, Declspec<"noreturn">];
// FIXME: Does GCC allow this on the function instead?
}
def NoInstrumentFunction : InheritableAttr {
let Spellings = [GNU<"no_instrument_function">,
CXX11<"gnu", "no_instrument_function">];
let Spellings = [GCC<"no_instrument_function">];
let Subjects = SubjectList<[Function]>;
}
def NoThrow : InheritableAttr {
let Spellings = [GNU<"nothrow">, CXX11<"gnu", "nothrow">,
Declspec<"nothrow">];
let Spellings = [GCC<"nothrow">, Declspec<"nothrow">];
}
def ObjCBridge : InheritableAttr {
@ -825,7 +822,7 @@ def ObjCDesignatedInitializer : Attr {
def Overloadable : Attr {
let Spellings = [GNU<"overloadable">];
let Subjects = SubjectList<[FunctionDefinition], ErrorDiag>;
let Subjects = SubjectList<[Function], ErrorDiag>;
}
def Override : InheritableAttr {
@ -852,7 +849,7 @@ def Ownership : InheritableAttr {
}
def Packed : InheritableAttr {
let Spellings = [GNU<"packed">, CXX11<"gnu", "packed">];
let Spellings = [GCC<"packed">];
// let Subjects = [Tag, Field];
}
@ -867,7 +864,7 @@ def IntelOclBicc : InheritableAttr {
}
def Pcs : InheritableAttr {
let Spellings = [GNU<"pcs">, CXX11<"gnu", "pcs">];
let Spellings = [GCC<"pcs">];
let Args = [EnumArgument<"PCS", "PCSType",
["aapcs", "aapcs-vfp"],
["AAPCS", "AAPCS_VFP"]>];
@ -875,11 +872,11 @@ def Pcs : InheritableAttr {
}
def Pure : InheritableAttr {
let Spellings = [GNU<"pure">, CXX11<"gnu", "pure">];
let Spellings = [GCC<"pure">];
}
def Regparm : TypeAttr {
let Spellings = [GNU<"regparm">, CXX11<"gnu", "regparm">];
let Spellings = [GCC<"regparm">];
let Args = [UnsignedArgument<"NumParams">];
let ASTNode = 0;
}
@ -906,7 +903,7 @@ def InitPriority : InheritableAttr {
}
def Section : InheritableAttr {
let Spellings = [GNU<"section">, CXX11<"gnu", "section">];
let Spellings = [GCC<"section">];
let Args = [StringArgument<"Name">];
let Subjects = SubjectList<[Function, GlobalVar,
ObjCMethod, ObjCProperty], ErrorDiag,
@ -914,26 +911,25 @@ def Section : InheritableAttr {
}
def Sentinel : InheritableAttr {
let Spellings = [GNU<"sentinel">, CXX11<"gnu", "sentinel">];
let Spellings = [GCC<"sentinel">];
let Args = [DefaultIntArgument<"Sentinel", 0>,
DefaultIntArgument<"NullPos", 0>];
// let Subjects = SubjectList<[Function, ObjCMethod, Block, Var]>;
}
def StdCall : InheritableAttr {
let Spellings = [GNU<"stdcall">, CXX11<"gnu", "stdcall">,
Keyword<"__stdcall">, Keyword<"_stdcall">];
let Spellings = [GCC<"stdcall">, Keyword<"__stdcall">, Keyword<"_stdcall">];
// let Subjects = [Function, ObjCMethod];
}
def SysVABI : InheritableAttr {
let Spellings = [GNU<"sysv_abi">, CXX11<"gnu", "sysv_abi">];
let Spellings = [GCC<"sysv_abi">];
// let Subjects = [Function, ObjCMethod];
}
def ThisCall : InheritableAttr {
let Spellings = [GNU<"thiscall">, CXX11<"gnu", "thiscall">,
Keyword<"__thiscall">, Keyword<"_thiscall">];
let Spellings = [GCC<"thiscall">, Keyword<"__thiscall">,
Keyword<"_thiscall">];
// let Subjects = [Function, ObjCMethod];
}
@ -943,7 +939,7 @@ def Pascal : InheritableAttr {
}
def TransparentUnion : InheritableAttr {
let Spellings = [GNU<"transparent_union">, CXX11<"gnu", "transparent_union">];
let Spellings = [GCC<"transparent_union">];
// let Subjects = SubjectList<[Record, TypedefName]>;
}
@ -974,14 +970,14 @@ def ObjCRequiresPropertyDefs : InheritableAttr {
}
def Unused : InheritableAttr {
let Spellings = [GNU<"unused">, CXX11<"gnu", "unused">];
let Spellings = [GCC<"unused">];
let Subjects = SubjectList<[Var, ObjCIvar, Type, Label, Field, ObjCMethod,
FunctionLike], WarnDiag,
"ExpectedVariableFunctionOrLabel">;
}
def Used : InheritableAttr {
let Spellings = [GNU<"used">, CXX11<"gnu", "used">];
let Spellings = [GCC<"used">];
}
def Uuid : InheritableAttr {
@ -992,7 +988,7 @@ def Uuid : InheritableAttr {
}
def VectorSize : TypeAttr {
let Spellings = [GNU<"vector_size">, CXX11<"gnu", "vector_size">];
let Spellings = [GCC<"vector_size">];
let Args = [ExprArgument<"NumBytes">];
}
@ -1004,7 +1000,7 @@ def VecTypeHint : InheritableAttr {
def Visibility : InheritableAttr {
let Clone = 0;
let Spellings = [GNU<"visibility">, CXX11<"gnu", "visibility">];
let Spellings = [GCC<"visibility">];
let Args = [EnumArgument<"Visibility", "VisibilityType",
["default", "hidden", "internal", "protected"],
["Default", "Hidden", "Hidden", "Protected"]>];
@ -1030,15 +1026,14 @@ def WarnUnused : InheritableAttr {
}
def WarnUnusedResult : InheritableAttr {
let Spellings = [GNU<"warn_unused_result">,
CXX11<"clang", "warn_unused_result">,
CXX11<"gnu", "warn_unused_result">];
let Spellings = [GCC<"warn_unused_result">,
CXX11<"clang", "warn_unused_result">];
let Subjects = SubjectList<[ObjCMethod, CXXRecord, FunctionLike], WarnDiag,
"ExpectedFunctionMethodOrClass">;
}
def Weak : InheritableAttr {
let Spellings = [GNU<"weak">, CXX11<"gnu", "weak">];
let Spellings = [GCC<"weak">];
let Subjects = SubjectList<[Var, Function, CXXRecord]>;
}
@ -1047,7 +1042,7 @@ def WeakImport : InheritableAttr {
}
def WeakRef : InheritableAttr {
let Spellings = [GNU<"weakref">, CXX11<"gnu", "weakref">];
let Spellings = [GCC<"weakref">];
// A WeakRef that has an argument is treated as being an AliasAttr
let Args = [StringArgument<"Aliasee", 1>];
let Subjects = SubjectList<[Var, Function], ErrorDiag>;
@ -1062,10 +1057,8 @@ def X86ForceAlignArgPointer : InheritableAttr, TargetSpecificAttr<TargetX86> {
// Attribute to disable AddressSanitizer (or equivalent) checks.
def NoSanitizeAddress : InheritableAttr {
let Spellings = [GNU<"no_address_safety_analysis">,
GNU<"no_sanitize_address">,
CXX11<"gnu", "no_address_safety_analysis">,
CXX11<"gnu", "no_sanitize_address">];
let Spellings = [GCC<"no_address_safety_analysis">,
GCC<"no_sanitize_address">];
let Subjects = SubjectList<[Function, FunctionTemplate], ErrorDiag>;
}
@ -1107,7 +1100,7 @@ def ScopedLockable : InheritableAttr {
def NoThreadSafetyAnalysis : InheritableAttr {
let Spellings = [GNU<"no_thread_safety_analysis">];
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
def GuardedBy : InheritableAttr {
@ -1161,7 +1154,7 @@ def ExclusiveLockFunction : InheritableAttr {
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
def SharedLockFunction : InheritableAttr {
@ -1171,7 +1164,7 @@ def SharedLockFunction : InheritableAttr {
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
def AssertExclusiveLock : InheritableAttr {
@ -1181,7 +1174,7 @@ def AssertExclusiveLock : InheritableAttr {
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
def AssertSharedLock : InheritableAttr {
@ -1191,7 +1184,7 @@ def AssertSharedLock : InheritableAttr {
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
// The first argument is an integer or boolean value specifying the return value
@ -1203,7 +1196,7 @@ def ExclusiveTrylockFunction : InheritableAttr {
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
// The first argument is an integer or boolean value specifying the return value
@ -1215,7 +1208,7 @@ def SharedTrylockFunction : InheritableAttr {
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
def UnlockFunction : InheritableAttr {
@ -1225,7 +1218,7 @@ def UnlockFunction : InheritableAttr {
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
def LockReturned : InheritableAttr {
@ -1234,7 +1227,7 @@ def LockReturned : InheritableAttr {
let LateParsed = 1;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
def LocksExcluded : InheritableAttr {
@ -1244,7 +1237,7 @@ def LocksExcluded : InheritableAttr {
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
def ExclusiveLocksRequired : InheritableAttr {
@ -1254,7 +1247,7 @@ def ExclusiveLocksRequired : InheritableAttr {
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
def SharedLocksRequired : InheritableAttr {
@ -1264,7 +1257,7 @@ def SharedLocksRequired : InheritableAttr {
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let DuplicatesAllowedWhileMerging = 1;
let Subjects = SubjectList<[FunctionDefinition, FunctionTemplate]>;
let Subjects = SubjectList<[Function, FunctionTemplate]>;
}
// C/C++ consumed attributes.
@ -1356,19 +1349,17 @@ def MsProperty : IgnoredAttr {
}
def MsStruct : InheritableAttr {
let Spellings = [GNU<"ms_struct">, CXX11<"gnu", "ms_struct">];
let Spellings = [GCC<"ms_struct">];
let Subjects = SubjectList<[Record]>;
}
def DLLExport : InheritableAttr, TargetSpecificAttr<TargetX86Win> {
let Spellings = [Declspec<"dllexport">, GNU<"dllexport">,
CXX11<"gnu", "dllexport">];
let Spellings = [Declspec<"dllexport">, GCC<"dllexport">];
let Subjects = SubjectList<[Function, Var]>;
}
def DLLImport : InheritableAttr, TargetSpecificAttr<TargetX86Win> {
let Spellings = [Declspec<"dllimport">, GNU<"dllimport">,
CXX11<"gnu", "dllimport">];
let Spellings = [Declspec<"dllimport">, GCC<"dllimport">];
// Technically, the subjects for DllImport are Function and Var, but there is
// custom semantic handling required when MicrosoftExt is true.
}

View File

@ -494,7 +494,7 @@ public:
bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const;
bool diagnoseLangOpts(class Sema &S) const;
bool existsInTarget(llvm::Triple T) const;
bool canAppearOnFunctionDefinition() const;
bool isKnownToGCC() const;
/// \brief If the parsed attribute has a semantic equivalent, and it would
/// have a semantic Spelling enumeration (due to having semantically-distinct

View File

@ -1143,7 +1143,7 @@ void Parser::ParseLexedAttribute(LateParsedAttribute &LA,
const AttributeList *AL = Attrs.getList();
if (OnDefinition && AL && !AL->isCXX11Attribute() &&
!AL->canAppearOnFunctionDefinition())
AL->isKnownToGCC())
Diag(Tok, diag::warn_attribute_on_function_definition)
<< &LA.AttrName;

View File

@ -1055,7 +1055,7 @@ Decl *Parser::ParseFunctionDefinition(ParsingDeclarator &D,
if (Tok.isNot(tok::equal)) {
AttributeList *DtorAttrs = D.getAttributes();
while (DtorAttrs) {
if (!DtorAttrs->canAppearOnFunctionDefinition() &&
if (DtorAttrs->isKnownToGCC() &&
!DtorAttrs->isCXX11Attribute()) {
Diag(DtorAttrs->getLoc(), diag::warn_attribute_on_function_definition)
<< DtorAttrs->getName();

View File

@ -150,7 +150,7 @@ struct ParsedAttrInfo {
unsigned HasCustomParsing : 1;
unsigned IsTargetSpecific : 1;
unsigned IsType : 1;
unsigned CanAppearOnFuncDef : 1;
unsigned IsKnownToGCC : 1;
bool (*DiagAppertainsToDecl)(Sema &S, const AttributeList &Attr,
const Decl *);
@ -199,8 +199,8 @@ bool AttributeList::existsInTarget(llvm::Triple T) const {
return getInfo(*this).ExistsInTarget(T);
}
bool AttributeList::canAppearOnFunctionDefinition() const {
return getInfo(*this).CanAppearOnFuncDef;
bool AttributeList::isKnownToGCC() const {
return getInfo(*this).IsKnownToGCC;
}
unsigned AttributeList::getSemanticSpelling() const {

View File

@ -26,6 +26,54 @@
using namespace llvm;
class FlattenedSpelling {
std::string V, N, NS;
bool K;
public:
FlattenedSpelling(const std::string &Variety, const std::string &Name,
const std::string &Namespace, bool KnownToGCC) :
V(Variety), N(Name), NS(Namespace), K(KnownToGCC) {}
explicit FlattenedSpelling(const Record &Spelling) :
V(Spelling.getValueAsString("Variety")),
N(Spelling.getValueAsString("Name")) {
assert(V != "GCC" && "Given a GCC spelling, which means this hasn't been"
"flattened!");
if (V == "CXX11")
NS = Spelling.getValueAsString("Namespace");
bool Unset;
K = Spelling.getValueAsBitOrUnset("KnownToGCC", Unset);
}
const std::string &variety() const { return V; }
const std::string &name() const { return N; }
const std::string &nameSpace() const { return NS; }
bool knownToGCC() const { return K; }
};
std::vector<FlattenedSpelling> GetFlattenedSpellings(const Record &Attr) {
std::vector<Record *> Spellings = Attr.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Ret;
for (std::vector<Record *>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I) {
const Record &Spelling = **I;
if (Spelling.getValueAsString("Variety") == "GCC") {
// Gin up two new spelling objects to add into the list.
Ret.push_back(FlattenedSpelling("GNU", Spelling.getValueAsString("Name"),
"", true));
Ret.push_back(FlattenedSpelling("CXX11",
Spelling.getValueAsString("Name"),
"gnu", true));
} else
Ret.push_back(FlattenedSpelling(Spelling));
}
return Ret;
}
static std::string ReadPCHRecord(StringRef type) {
return StringSwitch<std::string>(type)
.EndsWith("Decl *", "GetLocalDeclAs<"
@ -980,7 +1028,7 @@ static void writeAvailabilityValue(raw_ostream &OS) {
}
static void writeGetSpellingFunction(Record &R, raw_ostream &OS) {
std::vector<Record *> Spellings = R.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
OS << "const char *" << R.getName() << "Attr::getSpelling() const {\n";
if (Spellings.empty()) {
@ -995,7 +1043,7 @@ static void writeGetSpellingFunction(Record &R, raw_ostream &OS) {
for (unsigned I = 0; I < Spellings.size(); ++I)
OS << " case " << I << ":\n"
" return \"" << Spellings[I]->getValueAsString("Name") << "\";\n";
" return \"" << Spellings[I].name() << "\";\n";
// End of the switch statement.
OS << " }\n";
// End of the getSpelling function.
@ -1004,7 +1052,7 @@ static void writeGetSpellingFunction(Record &R, raw_ostream &OS) {
static void writePrettyPrintFunction(Record &R, std::vector<Argument*> &Args,
raw_ostream &OS) {
std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
OS << "void " << R.getName() << "Attr::printPretty("
<< "raw_ostream &OS, const PrintingPolicy &Policy) const {\n";
@ -1026,8 +1074,8 @@ static void writePrettyPrintFunction(Record &R, std::vector<Argument*> &Args,
// The actual spelling of the name and namespace (if applicable)
// of an attribute without considering prefix and suffix.
llvm::SmallString<64> Spelling;
std::string Name = Spellings[I]->getValueAsString("Name");
std::string Variety = Spellings[I]->getValueAsString("Variety");
std::string Name = Spellings[I].name();
std::string Variety = Spellings[I].variety();
if (Variety == "GNU") {
Prefix = " __attribute__((";
@ -1035,7 +1083,7 @@ static void writePrettyPrintFunction(Record &R, std::vector<Argument*> &Args,
} else if (Variety == "CXX11") {
Prefix = " [[";
Suffix = "]]";
std::string Namespace = Spellings[I]->getValueAsString("Namespace");
std::string Namespace = Spellings[I].nameSpace();
if (Namespace != "") {
Spelling += Namespace;
Spelling += "::";
@ -1082,19 +1130,18 @@ static void writePrettyPrintFunction(Record &R, std::vector<Argument*> &Args,
}
/// \brief Return the index of a spelling in a spelling list.
static unsigned getSpellingListIndex(const std::vector<Record*> &SpellingList,
const Record &Spelling) {
static unsigned
getSpellingListIndex(const std::vector<FlattenedSpelling> &SpellingList,
const FlattenedSpelling &Spelling) {
assert(SpellingList.size() && "Spelling list is empty!");
for (unsigned Index = 0; Index < SpellingList.size(); ++Index) {
Record *S = SpellingList[Index];
if (S->getValueAsString("Variety") != Spelling.getValueAsString("Variety"))
const FlattenedSpelling &S = SpellingList[Index];
if (S.variety() != Spelling.variety())
continue;
if (S->getValueAsString("Variety") == "CXX11" &&
S->getValueAsString("Namespace") !=
Spelling.getValueAsString("Namespace"))
if (S.nameSpace() != Spelling.nameSpace())
continue;
if (S->getValueAsString("Name") != Spelling.getValueAsString("Name"))
if (S.name() != Spelling.name())
continue;
return Index;
@ -1109,15 +1156,15 @@ static void writeAttrAccessorDefinition(Record &R, raw_ostream &OS) {
E = Accessors.end(); I != E; ++I) {
Record *Accessor = *I;
std::string Name = Accessor->getValueAsString("Name");
std::vector<Record*> Spellings = Accessor->getValueAsListOfDefs(
"Spellings");
std::vector<Record*> SpellingList = R.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Spellings =
GetFlattenedSpellings(*Accessor);
std::vector<FlattenedSpelling> SpellingList = GetFlattenedSpellings(R);
assert(SpellingList.size() &&
"Attribute with empty spelling list can't have accessors!");
OS << " bool " << Name << "() const { return SpellingListIndex == ";
for (unsigned Index = 0; Index < Spellings.size(); ++Index) {
OS << getSpellingListIndex(SpellingList, *Spellings[Index]);
OS << getSpellingListIndex(SpellingList, Spellings[Index]);
if (Index != Spellings.size() -1)
OS << " ||\n SpellingListIndex == ";
else
@ -1126,14 +1173,14 @@ static void writeAttrAccessorDefinition(Record &R, raw_ostream &OS) {
}
}
static bool SpellingNamesAreCommon(const std::vector<Record *>& Spellings) {
static bool
SpellingNamesAreCommon(const std::vector<FlattenedSpelling>& Spellings) {
assert(!Spellings.empty() && "An empty list of spellings was provided");
std::string FirstName = NormalizeNameForSpellingComparison(
Spellings.front()->getValueAsString("Name"));
for (std::vector<Record *>::const_iterator I = llvm::next(Spellings.begin()),
E = Spellings.end(); I != E; ++I) {
std::string Name = NormalizeNameForSpellingComparison(
(*I)->getValueAsString("Name"));
Spellings.front().name());
for (std::vector<FlattenedSpelling>::const_iterator
I = llvm::next(Spellings.begin()), E = Spellings.end(); I != E; ++I) {
std::string Name = NormalizeNameForSpellingComparison(I->name());
if (Name != FirstName)
return false;
}
@ -1142,7 +1189,7 @@ static bool SpellingNamesAreCommon(const std::vector<Record *>& Spellings) {
typedef std::map<unsigned, std::string> SemanticSpellingMap;
static std::string
CreateSemanticSpellings(const std::vector<Record *> &Spellings,
CreateSemanticSpellings(const std::vector<FlattenedSpelling> &Spellings,
SemanticSpellingMap &Map) {
// The enumerants are automatically generated based on the variety,
// namespace (if present) and name for each attribute spelling. However,
@ -1151,17 +1198,14 @@ CreateSemanticSpellings(const std::vector<Record *> &Spellings,
std::string Ret(" enum Spelling {\n");
std::set<std::string> Uniques;
unsigned Idx = 0;
for (std::vector<Record *>::const_iterator I = Spellings.begin(),
for (std::vector<FlattenedSpelling>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I, ++Idx) {
const Record &S = **I;
std::string Variety = S.getValueAsString("Variety");
std::string Spelling = S.getValueAsString("Name");
std::string Namespace = "";
const FlattenedSpelling &S = *I;
std::string Variety = S.variety();
std::string Spelling = S.name();
std::string Namespace = S.nameSpace();
std::string EnumName = "";
if (Variety == "CXX11")
Namespace = S.getValueAsString("Namespace");
EnumName += (Variety + "_");
if (!Namespace.empty())
EnumName += (NormalizeNameForSpellingComparison(Namespace).str() +
@ -1250,7 +1294,7 @@ void EmitClangAttrClass(RecordKeeper &Records, raw_ostream &OS) {
OS << "\npublic:\n";
std::vector<Record *> Spellings = R.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
// If there are zero or one spellings, all spelling-related functionality
// can be elided. If all of the spellings share the same name, the spelling
@ -1425,13 +1469,12 @@ void EmitClangAttrTypeArgList(RecordKeeper &Records, raw_ostream &OS) {
continue;
// All these spellings take a single type argument.
std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
std::set<std::string> Emitted;
for (std::vector<Record*>::const_iterator I = Spellings.begin(),
for (std::vector<FlattenedSpelling>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I) {
if (Emitted.insert((*I)->getValueAsString("Name")).second)
OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", "
<< "true" << ")\n";
if (Emitted.insert(I->name()).second)
OS << ".Case(\"" << I->name() << "\", " << "true" << ")\n";
}
}
}
@ -1451,13 +1494,12 @@ void EmitClangAttrArgContextList(RecordKeeper &Records, raw_ostream &OS) {
continue;
// All these spellings take are parsed unevaluated.
std::vector<Record *> Spellings = Attr.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
std::set<std::string> Emitted;
for (std::vector<Record*>::const_iterator I = Spellings.begin(),
for (std::vector<FlattenedSpelling>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I) {
if (Emitted.insert((*I)->getValueAsString("Name")).second)
OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", "
<< "true" << ")\n";
if (Emitted.insert(I->name()).second)
OS << ".Case(\"" << I->name() << "\", " << "true" << ")\n";
}
}
@ -1480,13 +1522,12 @@ void EmitClangAttrIdentifierArgList(RecordKeeper &Records, raw_ostream &OS) {
continue;
// All these spellings take an identifier argument.
std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
std::set<std::string> Emitted;
for (std::vector<Record*>::const_iterator I = Spellings.begin(),
for (std::vector<FlattenedSpelling>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I) {
if (Emitted.insert((*I)->getValueAsString("Name")).second)
OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", "
<< "true" << ")\n";
if (Emitted.insert(I->name()).second)
OS << ".Case(\"" << I->name() << "\", " << "true" << ")\n";
}
}
}
@ -1728,12 +1769,10 @@ void EmitClangAttrSpellingList(RecordKeeper &Records, raw_ostream &OS) {
} else
Test = "true";
std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings");
for (std::vector<Record*>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I) {
OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", " << Test;
OS << ")\n";
}
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
for (std::vector<FlattenedSpelling>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I)
OS << ".Case(\"" << I->name() << "\", " << Test << ")\n";
}
}
@ -1752,25 +1791,19 @@ void EmitClangAttrSpellingListIndex(RecordKeeper &Records, raw_ostream &OS) {
for (ParsedAttrMap::const_iterator I = Attrs.begin(), E = Attrs.end();
I != E; ++I) {
Record &R = *I->second;
std::vector<Record*> Spellings = R.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
OS << " case AT_" << I->first << ": {\n";
for (unsigned I = 0; I < Spellings.size(); ++ I) {
SmallString<16> Namespace;
if (Spellings[I]->getValueAsString("Variety") == "CXX11")
Namespace = Spellings[I]->getValueAsString("Namespace");
else
Namespace = "";
OS << " if (Name == \""
<< Spellings[I]->getValueAsString("Name") << "\" && "
<< Spellings[I].name() << "\" && "
<< "SyntaxUsed == "
<< StringSwitch<unsigned>(Spellings[I]->getValueAsString("Variety"))
<< StringSwitch<unsigned>(Spellings[I].variety())
.Case("GNU", 0)
.Case("CXX11", 1)
.Case("Declspec", 2)
.Case("Keyword", 3)
.Default(0)
<< " && Scope == \"" << Namespace << "\")\n"
<< " && Scope == \"" << Spellings[I].nameSpace() << "\")\n"
<< " return " << I << ";\n";
}
@ -1875,16 +1908,14 @@ void EmitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS) {
bool LateParsed = Attr.getValueAsBit("LateParsed");
if (LateParsed) {
std::vector<Record*> Spellings =
Attr.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
// FIXME: Handle non-GNU attributes
for (std::vector<Record*>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I) {
if ((*I)->getValueAsString("Variety") != "GNU")
for (std::vector<FlattenedSpelling>::const_iterator
I = Spellings.begin(), E = Spellings.end(); I != E; ++I) {
if (I->variety() != "GNU")
continue;
OS << ".Case(\"" << (*I)->getValueAsString("Name") << "\", "
<< LateParsed << ")\n";
OS << ".Case(\"" << I->name() << "\", " << LateParsed << ")\n";
}
}
}
@ -2044,7 +2075,6 @@ static std::string CalculateDiagnostic(const Record &S) {
uint32_t V = StringSwitch<uint32_t>(Name)
.Case("Function", Func)
.Case("FunctionDefinition", Func)
.Case("Var", Var)
.Case("ObjCMethod", ObjCMethod)
.Case("ParmVar", Param)
@ -2120,8 +2150,6 @@ static std::string GetSubjectWithSuffix(const Record *R) {
std::string B = R->getName();
if (B == "DeclBase")
return "Decl";
else if (B == "FunctionDefinition")
return "FunctionDecl";
return B + "Decl";
}
static std::string GenerateCustomAppertainsTo(const Record &Subject,
@ -2365,7 +2393,7 @@ static std::string GenerateSpellingIndexToSemanticSpelling(const Record &Attr,
if (!Attr.getValueAsBit("ASTNode"))
return "defaultSpellingIndexToSemanticSpelling";
std::vector<Record *> Spellings = Attr.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
// If there are zero or one spellings, or all of the spellings share the same
// name, we can also bail out early.
@ -2386,19 +2414,13 @@ static std::string GenerateSpellingIndexToSemanticSpelling(const Record &Attr,
return Name;
}
static bool CanAppearOnFuncDef(const Record &Attr) {
// Look at the subjects this function appertains to; if a FunctionDefinition
// appears in the list, then this attribute can appear on a function
// definition.
if (Attr.isValueUnset("Subjects"))
return false;
std::vector<Record *> Subjects = Attr.getValueAsDef("Subjects")->
getValueAsListOfDefs("Subjects");
for (std::vector<Record *>::const_iterator I = Subjects.begin(),
E = Subjects.end(); I != E; ++I) {
const Record &Subject = **I;
if (Subject.getName() == "FunctionDefinition")
static bool IsKnownToGCC(const Record &Attr) {
// Look at the spellings for this subject; if there are any spellings which
// claim to be known to GCC, the attribute is known to GCC.
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
for (std::vector<FlattenedSpelling>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I) {
if (I->knownToGCC())
return true;
}
return false;
@ -2440,7 +2462,7 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
SS << ", " << I->second->getValueAsBit("HasCustomParsing");
SS << ", " << I->second->isSubClassOf("TargetSpecificAttr");
SS << ", " << I->second->isSubClassOf("TypeAttr");
SS << ", " << CanAppearOnFuncDef(*I->second);
SS << ", " << IsKnownToGCC(*I->second);
SS << ", " << GenerateAppertainsTo(*I->second, OS);
SS << ", " << GenerateLangOptRequirements(*I->second, OS);
SS << ", " << GenerateTargetRequirements(*I->second, Dupes, OS);
@ -2492,15 +2514,15 @@ void EmitClangAttrParsedAttrKinds(RecordKeeper &Records, raw_ostream &OS) {
} else
AttrName = NormalizeAttrName(StringRef(Attr.getName())).str();
std::vector<Record*> Spellings = Attr.getValueAsListOfDefs("Spellings");
for (std::vector<Record*>::const_iterator I = Spellings.begin(),
E = Spellings.end(); I != E; ++I) {
std::string RawSpelling = (*I)->getValueAsString("Name");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attr);
for (std::vector<FlattenedSpelling>::const_iterator
I = Spellings.begin(), E = Spellings.end(); I != E; ++I) {
std::string RawSpelling = I->name();
std::vector<StringMatcher::StringPair> *Matches = 0;
std::string Spelling, Variety = (*I)->getValueAsString("Variety");
std::string Spelling, Variety = I->variety();
if (Variety == "CXX11") {
Matches = &CXX11;
Spelling += (*I)->getValueAsString("Namespace");
Spelling += I->nameSpace();
Spelling += "::";
} else if (Variety == "GNU")
Matches = &GNU;
@ -2557,7 +2579,7 @@ void EmitClangAttrDump(RecordKeeper &Records, raw_ostream &OS) {
// If the attribute has a semantically-meaningful name (which is determined
// by whether there is a Spelling enumeration for it), then write out the
// spelling used for the attribute.
std::vector<Record *> Spellings = R.getValueAsListOfDefs("Spellings");
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(R);
if (Spellings.size() > 1 && !SpellingNamesAreCommon(Spellings))
OS << " OS << \" \" << A->getSpelling();\n";