forked from OSchip/llvm-project
Use tablegen to diagnose mutually exclusive attributes
Currently, when one or more attributes are mutually exclusive, the developer adding the attribute has to manually emit diagnostics. In practice, this is highly error prone, especially for declaration attributes, because such checking is not trivial. Redeclarations require you to write a "merge" function to diagnose mutually exclusive attributes and most attributes get this wrong. This patch introduces a table-generated way to specify that a group of two or more attributes are mutually exclusive: def : MutualExclusions<[Attr1, Attr2, Attr3]>; This works for both statement and declaration attributes (but not type attributes) and the checking is done either from the common attribute diagnostic checking code or from within mergeDeclAttribute() when merging redeclarations.
This commit is contained in:
parent
f02c6984d7
commit
4be8a26951
|
@ -3033,6 +3033,13 @@ If additional functionality is desired for the semantic form of the attribute,
|
|||
the ``AdditionalMembers`` field specifies code to be copied verbatim into the
|
||||
semantic attribute class object, with ``public`` access.
|
||||
|
||||
If two or more attributes cannot be used in combination on the same declaration
|
||||
or statement, a ``MutualExclusions`` definition can be supplied to automatically
|
||||
generate diagnostic code. This will disallow the attribute combinations
|
||||
regardless of spellings used. Additionally, it will diagnose combinations within
|
||||
the same attribute list, different attribute list, and redeclarations, as
|
||||
appropriate.
|
||||
|
||||
Boilerplate
|
||||
^^^^^^^^^^^
|
||||
All semantic processing of declaration attributes happens in `lib/Sema/SemaDeclAttr.cpp
|
||||
|
|
|
@ -554,6 +554,11 @@ class Attr {
|
|||
list<Documentation> Documentation;
|
||||
}
|
||||
|
||||
/// Used to define a set of mutually exclusive attributes.
|
||||
class MutualExclusions<list<Attr> Ex> {
|
||||
list<Attr> Exclusions = Ex;
|
||||
}
|
||||
|
||||
/// A type attribute is not processed on a declaration or a statement.
|
||||
class TypeAttr : Attr;
|
||||
|
||||
|
@ -918,6 +923,7 @@ def CFAuditedTransfer : InheritableAttr {
|
|||
let Spellings = [Clang<"cf_audited_transfer">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [Undocumented];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
|
||||
// cf_unknown_transfer is an explicit opt-out of cf_audited_transfer.
|
||||
|
@ -927,7 +933,9 @@ def CFUnknownTransfer : InheritableAttr {
|
|||
let Spellings = [Clang<"cf_unknown_transfer">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [Undocumented];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
def : MutualExclusions<[CFAuditedTransfer, CFUnknownTransfer]>;
|
||||
|
||||
def CFReturnsRetained : InheritableAttr {
|
||||
let Spellings = [Clang<"cf_returns_retained">];
|
||||
|
@ -1009,6 +1017,7 @@ def Cold : InheritableAttr {
|
|||
let Spellings = [GCC<"cold">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [Undocumented];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
|
||||
def Common : InheritableAttr {
|
||||
|
@ -1094,6 +1103,7 @@ def CUDADeviceBuiltinSurfaceType : InheritableAttr {
|
|||
let Subjects = SubjectList<[CXXRecord]>;
|
||||
let Documentation = [CUDADeviceBuiltinSurfaceTypeDocs];
|
||||
let MeaningfulToClassTemplateDefinition = 1;
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
|
||||
def CUDADeviceBuiltinTextureType : InheritableAttr {
|
||||
|
@ -1103,7 +1113,10 @@ def CUDADeviceBuiltinTextureType : InheritableAttr {
|
|||
let Subjects = SubjectList<[CXXRecord]>;
|
||||
let Documentation = [CUDADeviceBuiltinTextureTypeDocs];
|
||||
let MeaningfulToClassTemplateDefinition = 1;
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
def : MutualExclusions<[CUDADeviceBuiltinSurfaceType,
|
||||
CUDADeviceBuiltinTextureType]>;
|
||||
|
||||
def CUDAGlobal : InheritableAttr {
|
||||
let Spellings = [GNU<"global">, Declspec<"__global__">];
|
||||
|
@ -1111,13 +1124,16 @@ def CUDAGlobal : InheritableAttr {
|
|||
let LangOpts = [CUDA];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
def : MutualExclusions<[CUDADevice, CUDAGlobal]>;
|
||||
|
||||
def CUDAHost : InheritableAttr {
|
||||
let Spellings = [GNU<"host">, Declspec<"__host__">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let LangOpts = [CUDA];
|
||||
let Documentation = [Undocumented];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
def : MutualExclusions<[CUDAGlobal, CUDAHost]>;
|
||||
|
||||
def HIPManaged : InheritableAttr {
|
||||
let Spellings = [GNU<"managed">, Declspec<"__managed__">];
|
||||
|
@ -1150,6 +1166,7 @@ def CUDAShared : InheritableAttr {
|
|||
let LangOpts = [CUDA];
|
||||
let Documentation = [Undocumented];
|
||||
}
|
||||
def : MutualExclusions<[CUDAConstant, CUDAShared, HIPManaged]>;
|
||||
|
||||
def SYCLKernel : InheritableAttr {
|
||||
let Spellings = [Clang<"sycl_kernel">];
|
||||
|
@ -1342,6 +1359,7 @@ def Unlikely : StmtAttr {
|
|||
let Spellings = [CXX11<"", "unlikely", 201803>, C2x<"clang", "unlikely">];
|
||||
let Documentation = [LikelihoodDocs];
|
||||
}
|
||||
def : MutualExclusions<[Likely, Unlikely]>;
|
||||
|
||||
def NoMerge : DeclOrStmtAttr {
|
||||
let Spellings = [Clang<"nomerge">];
|
||||
|
@ -1433,7 +1451,9 @@ def Hot : InheritableAttr {
|
|||
// An AST node is created for this attribute, but not actually used beyond
|
||||
// semantic checking for mutual exclusion with the Cold attribute.
|
||||
let Documentation = [Undocumented];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
def : MutualExclusions<[Hot, Cold]>;
|
||||
|
||||
def IBAction : InheritableAttr {
|
||||
let Spellings = [Clang<"ibaction">];
|
||||
|
@ -1544,6 +1564,7 @@ def Mips16 : InheritableAttr, TargetSpecificAttr<TargetMips32> {
|
|||
let Spellings = [GCC<"mips16">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [Undocumented];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
|
||||
def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips32> {
|
||||
|
@ -1562,24 +1583,30 @@ def MipsInterrupt : InheritableAttr, TargetSpecificAttr<TargetMips32> {
|
|||
let ParseKind = "Interrupt";
|
||||
let Documentation = [MipsInterruptDocs];
|
||||
}
|
||||
def : MutualExclusions<[Mips16, MipsInterrupt]>;
|
||||
|
||||
def MicroMips : InheritableAttr, TargetSpecificAttr<TargetMips32> {
|
||||
let Spellings = [GCC<"micromips">];
|
||||
let Subjects = SubjectList<[Function], ErrorDiag>;
|
||||
let Documentation = [MicroMipsDocs];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
def : MutualExclusions<[Mips16, MicroMips]>;
|
||||
|
||||
def MipsLongCall : InheritableAttr, TargetSpecificAttr<TargetAnyMips> {
|
||||
let Spellings = [GCC<"long_call">, GCC<"far">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [MipsLongCallStyleDocs];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
|
||||
def MipsShortCall : InheritableAttr, TargetSpecificAttr<TargetAnyMips> {
|
||||
let Spellings = [GCC<"short_call">, GCC<"near">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [MipsShortCallStyleDocs];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
def : MutualExclusions<[MipsLongCall, MipsShortCall]>;
|
||||
|
||||
def M68kInterrupt : InheritableAttr, TargetSpecificAttr<TargetM68k> {
|
||||
// NOTE: If you add any additional spellings, ARMInterrupt's, MipsInterrupt's
|
||||
|
@ -1656,7 +1683,9 @@ def DisableTailCalls : InheritableAttr {
|
|||
let Spellings = [Clang<"disable_tail_calls">];
|
||||
let Subjects = SubjectList<[Function, ObjCMethod]>;
|
||||
let Documentation = [DisableTailCallsDocs];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
def : MutualExclusions<[Naked, DisableTailCalls]>;
|
||||
|
||||
def NoAlias : InheritableAttr {
|
||||
let Spellings = [Declspec<"noalias">];
|
||||
|
@ -1930,7 +1959,9 @@ def NotTailCalled : InheritableAttr {
|
|||
let Spellings = [Clang<"not_tail_called">];
|
||||
let Subjects = SubjectList<[Function]>;
|
||||
let Documentation = [NotTailCalledDocs];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
def : MutualExclusions<[AlwaysInline, NotTailCalled]>;
|
||||
|
||||
def NoStackProtector : InheritableAttr {
|
||||
let Spellings = [Clang<"no_stack_protector">];
|
||||
|
@ -3248,6 +3279,7 @@ def Pointer : InheritableAttr {
|
|||
let Args = [TypeArgument<"DerefType", /*opt=*/1>];
|
||||
let Documentation = [LifetimePointerDocs];
|
||||
}
|
||||
def : MutualExclusions<[Owner, Pointer]>;
|
||||
|
||||
// Microsoft-related attributes
|
||||
|
||||
|
@ -3620,6 +3652,7 @@ def InternalLinkage : InheritableAttr {
|
|||
let Subjects = SubjectList<[Var, Function, CXXRecord]>;
|
||||
let Documentation = [InternalLinkageDocs];
|
||||
}
|
||||
def : MutualExclusions<[Common, InternalLinkage]>;
|
||||
|
||||
def ExcludeFromExplicitInstantiation : InheritableAttr {
|
||||
let Spellings = [Clang<"exclude_from_explicit_instantiation">];
|
||||
|
@ -3647,18 +3680,22 @@ def AlwaysDestroy : InheritableAttr {
|
|||
let Subjects = SubjectList<[Var]>;
|
||||
let Documentation = [AlwaysDestroyDocs];
|
||||
}
|
||||
def : MutualExclusions<[NoDestroy, AlwaysDestroy]>;
|
||||
|
||||
def SpeculativeLoadHardening : InheritableAttr {
|
||||
let Spellings = [Clang<"speculative_load_hardening">];
|
||||
let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>;
|
||||
let Documentation = [SpeculativeLoadHardeningDocs];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
|
||||
def NoSpeculativeLoadHardening : InheritableAttr {
|
||||
let Spellings = [Clang<"no_speculative_load_hardening">];
|
||||
let Subjects = SubjectList<[Function, ObjCMethod], ErrorDiag>;
|
||||
let Documentation = [NoSpeculativeLoadHardeningDocs];
|
||||
let SimpleHandler = 1;
|
||||
}
|
||||
def : MutualExclusions<[SpeculativeLoadHardening, NoSpeculativeLoadHardening]>;
|
||||
|
||||
def Uninitialized : InheritableAttr {
|
||||
let Spellings = [Clang<"uninitialized", 0>];
|
||||
|
|
|
@ -86,6 +86,18 @@ struct ParsedAttrInfo {
|
|||
const Stmt *St) const {
|
||||
return true;
|
||||
}
|
||||
/// Check if the given attribute is mutually exclusive with other attributes
|
||||
/// already applied to the given declaration.
|
||||
virtual bool diagMutualExclusion(Sema &S, const ParsedAttr &A,
|
||||
const Decl *D) const {
|
||||
return true;
|
||||
}
|
||||
/// Check if the given attribute is mutually exclusive with other attributes
|
||||
/// already applied to the given statement.
|
||||
virtual bool diagMutualExclusion(Sema &S, const ParsedAttr &A,
|
||||
const Stmt *St) const {
|
||||
return true;
|
||||
}
|
||||
/// Check if this attribute is allowed by the language we are compiling, and
|
||||
/// issue a diagnostic if not.
|
||||
virtual bool diagLangOpts(Sema &S, const ParsedAttr &Attr) const {
|
||||
|
@ -599,6 +611,8 @@ public:
|
|||
bool hasVariadicArg() const;
|
||||
bool diagnoseAppertainsTo(class Sema &S, const Decl *D) const;
|
||||
bool diagnoseAppertainsTo(class Sema &S, const Stmt *St) const;
|
||||
bool diagnoseMutualExclusion(class Sema &S, const Decl *D) const;
|
||||
bool diagnoseMutualExclusion(class Sema &S, const Stmt *St) const;
|
||||
bool appliesToDecl(const Decl *D, attr::SubjectMatchRule MatchRule) const;
|
||||
void getMatchRules(const LangOptions &LangOpts,
|
||||
SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>>
|
||||
|
|
|
@ -3304,12 +3304,6 @@ public:
|
|||
const AttributeCommonInfo &CI,
|
||||
const IdentifierInfo *Ident);
|
||||
MinSizeAttr *mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI);
|
||||
NoSpeculativeLoadHardeningAttr *
|
||||
mergeNoSpeculativeLoadHardeningAttr(Decl *D,
|
||||
const NoSpeculativeLoadHardeningAttr &AL);
|
||||
SpeculativeLoadHardeningAttr *
|
||||
mergeSpeculativeLoadHardeningAttr(Decl *D,
|
||||
const SpeculativeLoadHardeningAttr &AL);
|
||||
SwiftNameAttr *mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA,
|
||||
StringRef Name);
|
||||
OptimizeNoneAttr *mergeOptimizeNoneAttr(Decl *D,
|
||||
|
@ -3317,8 +3311,6 @@ public:
|
|||
InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D, const ParsedAttr &AL);
|
||||
InternalLinkageAttr *mergeInternalLinkageAttr(Decl *D,
|
||||
const InternalLinkageAttr &AL);
|
||||
CommonAttr *mergeCommonAttr(Decl *D, const ParsedAttr &AL);
|
||||
CommonAttr *mergeCommonAttr(Decl *D, const CommonAttr &AL);
|
||||
WebAssemblyImportNameAttr *mergeImportNameAttr(
|
||||
Decl *D, const WebAssemblyImportNameAttr &AL);
|
||||
WebAssemblyImportModuleAttr *mergeImportModuleAttr(
|
||||
|
|
|
@ -163,6 +163,14 @@ bool ParsedAttr::diagnoseAppertainsTo(Sema &S, const Stmt *St) const {
|
|||
return getInfo().diagAppertainsToStmt(S, *this, St);
|
||||
}
|
||||
|
||||
bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Decl *D) const {
|
||||
return getInfo().diagMutualExclusion(S, *this, D);
|
||||
}
|
||||
|
||||
bool ParsedAttr::diagnoseMutualExclusion(Sema &S, const Stmt *St) const {
|
||||
return getInfo().diagMutualExclusion(S, *this, St);
|
||||
}
|
||||
|
||||
bool ParsedAttr::appliesToDecl(const Decl *D,
|
||||
attr::SubjectMatchRule MatchRule) const {
|
||||
return checkAttributeMatchRuleAppliesTo(D, MatchRule);
|
||||
|
|
|
@ -1206,6 +1206,10 @@ static bool checkCommonAttributeFeatures(Sema& S, const Ty *Node,
|
|||
// Check whether the attribute appertains to the given subject.
|
||||
if (!A.diagnoseAppertainsTo(S, Node))
|
||||
return true;
|
||||
// Check whether the attribute is mutually exclusive with other attributes
|
||||
// that have already been applied to the declaration.
|
||||
if (!A.diagnoseMutualExclusion(S, Node))
|
||||
return true;
|
||||
// Check whether the attribute exists in the target architecture.
|
||||
if (S.CheckAttrTarget(A))
|
||||
return true;
|
||||
|
|
|
@ -2540,9 +2540,18 @@ static bool mergeAlignedAttrs(Sema &S, NamedDecl *New, Decl *Old) {
|
|||
return AnyAdded;
|
||||
}
|
||||
|
||||
#define WANT_MERGE_LOGIC
|
||||
#include "clang/Sema/AttrParsedAttrImpl.inc"
|
||||
#undef WANT_MERGE_LOGIC
|
||||
|
||||
static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
|
||||
const InheritableAttr *Attr,
|
||||
Sema::AvailabilityMergeKind AMK) {
|
||||
// Diagnose any mutual exclusions between the attribute that we want to add
|
||||
// and attributes that already exist on the declaration.
|
||||
if (!DiagnoseMutualExclusions(S, D, Attr))
|
||||
return false;
|
||||
|
||||
// This function copies an attribute Attr from a previous declaration to the
|
||||
// new declaration D if the new declaration doesn't itself have that attribute
|
||||
// yet or if that attribute allows duplicates.
|
||||
|
@ -2592,8 +2601,6 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
|
|||
NewAttr = S.mergeOptimizeNoneAttr(D, *OA);
|
||||
else if (const auto *InternalLinkageA = dyn_cast<InternalLinkageAttr>(Attr))
|
||||
NewAttr = S.mergeInternalLinkageAttr(D, *InternalLinkageA);
|
||||
else if (const auto *CommonA = dyn_cast<CommonAttr>(Attr))
|
||||
NewAttr = S.mergeCommonAttr(D, *CommonA);
|
||||
else if (isa<AlignedAttr>(Attr))
|
||||
// AlignedAttrs are handled separately, because we need to handle all
|
||||
// such attributes on a declaration at the same time.
|
||||
|
@ -2604,10 +2611,6 @@ static bool mergeDeclAttribute(Sema &S, NamedDecl *D,
|
|||
NewAttr = nullptr;
|
||||
else if (const auto *UA = dyn_cast<UuidAttr>(Attr))
|
||||
NewAttr = S.mergeUuidAttr(D, *UA, UA->getGuid(), UA->getGuidDecl());
|
||||
else if (const auto *SLHA = dyn_cast<SpeculativeLoadHardeningAttr>(Attr))
|
||||
NewAttr = S.mergeSpeculativeLoadHardeningAttr(D, *SLHA);
|
||||
else if (const auto *SLHA = dyn_cast<NoSpeculativeLoadHardeningAttr>(Attr))
|
||||
NewAttr = S.mergeNoSpeculativeLoadHardeningAttr(D, *SLHA);
|
||||
else if (const auto *IMA = dyn_cast<WebAssemblyImportModuleAttr>(Attr))
|
||||
NewAttr = S.mergeImportModuleAttr(D, *IMA);
|
||||
else if (const auto *INA = dyn_cast<WebAssemblyImportNameAttr>(Attr))
|
||||
|
|
|
@ -407,24 +407,6 @@ static void handleSimpleAttributeOrDiagnose(Sema &S, Decl *D,
|
|||
handleSimpleAttribute<AttrType>(S, D, CI);
|
||||
}
|
||||
|
||||
template <typename AttrType>
|
||||
static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D,
|
||||
const ParsedAttr &AL) {
|
||||
handleSimpleAttribute<AttrType>(S, D, AL);
|
||||
}
|
||||
|
||||
/// Applies the given attribute to the Decl so long as the Decl doesn't
|
||||
/// already have one of the given incompatible attributes.
|
||||
template <typename AttrType, typename IncompatibleAttrType,
|
||||
typename... IncompatibleAttrTypes>
|
||||
static void handleSimpleAttributeWithExclusions(Sema &S, Decl *D,
|
||||
const ParsedAttr &AL) {
|
||||
if (checkAttrMutualExclusion<IncompatibleAttrType>(S, D, AL))
|
||||
return;
|
||||
handleSimpleAttributeWithExclusions<AttrType, IncompatibleAttrTypes...>(S, D,
|
||||
AL);
|
||||
}
|
||||
|
||||
/// Check if the passed-in expression is of type int or bool.
|
||||
static bool isIntOrBool(Expr *Exp) {
|
||||
QualType QT = Exp->getType();
|
||||
|
@ -2021,8 +2003,7 @@ static void handleCommonAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
return;
|
||||
}
|
||||
|
||||
if (CommonAttr *CA = S.mergeCommonAttr(D, AL))
|
||||
D->addAttr(CA);
|
||||
D->addAttr(::new (S.Context) CommonAttr(S.Context, AL));
|
||||
}
|
||||
|
||||
static void handleCmseNSEntryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
|
@ -2041,9 +2022,6 @@ static void handleCmseNSEntryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
}
|
||||
|
||||
static void handleNakedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
if (checkAttrMutualExclusion<DisableTailCallsAttr>(S, D, AL))
|
||||
return;
|
||||
|
||||
if (AL.isDeclspecAttribute()) {
|
||||
const auto &Triple = S.getASTContext().getTargetInfo().getTriple();
|
||||
const auto &Arch = Triple.getArch();
|
||||
|
@ -4302,20 +4280,6 @@ AlwaysInlineAttr *Sema::mergeAlwaysInlineAttr(Decl *D,
|
|||
return ::new (Context) AlwaysInlineAttr(Context, CI);
|
||||
}
|
||||
|
||||
CommonAttr *Sema::mergeCommonAttr(Decl *D, const ParsedAttr &AL) {
|
||||
if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL))
|
||||
return nullptr;
|
||||
|
||||
return ::new (Context) CommonAttr(Context, AL);
|
||||
}
|
||||
|
||||
CommonAttr *Sema::mergeCommonAttr(Decl *D, const CommonAttr &AL) {
|
||||
if (checkAttrMutualExclusion<InternalLinkageAttr>(*this, D, AL))
|
||||
return nullptr;
|
||||
|
||||
return ::new (Context) CommonAttr(Context, AL);
|
||||
}
|
||||
|
||||
InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D,
|
||||
const ParsedAttr &AL) {
|
||||
if (const auto *VD = dyn_cast<VarDecl>(D)) {
|
||||
|
@ -4334,9 +4298,6 @@ InternalLinkageAttr *Sema::mergeInternalLinkageAttr(Decl *D,
|
|||
}
|
||||
}
|
||||
|
||||
if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL))
|
||||
return nullptr;
|
||||
|
||||
return ::new (Context) InternalLinkageAttr(Context, AL);
|
||||
}
|
||||
InternalLinkageAttr *
|
||||
|
@ -4357,9 +4318,6 @@ Sema::mergeInternalLinkageAttr(Decl *D, const InternalLinkageAttr &AL) {
|
|||
}
|
||||
}
|
||||
|
||||
if (checkAttrMutualExclusion<CommonAttr>(*this, D, AL))
|
||||
return nullptr;
|
||||
|
||||
return ::new (Context) InternalLinkageAttr(Context, AL);
|
||||
}
|
||||
|
||||
|
@ -4376,14 +4334,6 @@ MinSizeAttr *Sema::mergeMinSizeAttr(Decl *D, const AttributeCommonInfo &CI) {
|
|||
return ::new (Context) MinSizeAttr(Context, CI);
|
||||
}
|
||||
|
||||
NoSpeculativeLoadHardeningAttr *Sema::mergeNoSpeculativeLoadHardeningAttr(
|
||||
Decl *D, const NoSpeculativeLoadHardeningAttr &AL) {
|
||||
if (checkAttrMutualExclusion<SpeculativeLoadHardeningAttr>(*this, D, AL))
|
||||
return nullptr;
|
||||
|
||||
return ::new (Context) NoSpeculativeLoadHardeningAttr(Context, AL);
|
||||
}
|
||||
|
||||
SwiftNameAttr *Sema::mergeSwiftNameAttr(Decl *D, const SwiftNameAttr &SNA,
|
||||
StringRef Name) {
|
||||
if (const auto *PrevSNA = D->getAttr<SwiftNameAttr>()) {
|
||||
|
@ -4417,18 +4367,7 @@ OptimizeNoneAttr *Sema::mergeOptimizeNoneAttr(Decl *D,
|
|||
return ::new (Context) OptimizeNoneAttr(Context, CI);
|
||||
}
|
||||
|
||||
SpeculativeLoadHardeningAttr *Sema::mergeSpeculativeLoadHardeningAttr(
|
||||
Decl *D, const SpeculativeLoadHardeningAttr &AL) {
|
||||
if (checkAttrMutualExclusion<NoSpeculativeLoadHardeningAttr>(*this, D, AL))
|
||||
return nullptr;
|
||||
|
||||
return ::new (Context) SpeculativeLoadHardeningAttr(Context, AL);
|
||||
}
|
||||
|
||||
static void handleAlwaysInlineAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
if (checkAttrMutualExclusion<NotTailCalledAttr>(S, D, AL))
|
||||
return;
|
||||
|
||||
if (AlwaysInlineAttr *Inline =
|
||||
S.mergeAlwaysInlineAttr(D, AL, AL.getAttrName()))
|
||||
D->addAttr(Inline);
|
||||
|
@ -4445,9 +4384,6 @@ static void handleOptimizeNoneAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
}
|
||||
|
||||
static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
if (checkAttrMutualExclusion<CUDASharedAttr>(S, D, AL) ||
|
||||
checkAttrMutualExclusion<HIPManagedAttr>(S, D, AL))
|
||||
return;
|
||||
const auto *VD = cast<VarDecl>(D);
|
||||
if (VD->hasLocalStorage()) {
|
||||
S.Diag(AL.getLoc(), diag::err_cuda_nonstatic_constdev);
|
||||
|
@ -4457,9 +4393,6 @@ static void handleConstantAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
}
|
||||
|
||||
static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, AL) ||
|
||||
checkAttrMutualExclusion<HIPManagedAttr>(S, D, AL))
|
||||
return;
|
||||
const auto *VD = cast<VarDecl>(D);
|
||||
// extern __shared__ is only allowed on arrays with no length (e.g.
|
||||
// "int x[]").
|
||||
|
@ -4476,10 +4409,6 @@ static void handleSharedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
}
|
||||
|
||||
static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
if (checkAttrMutualExclusion<CUDADeviceAttr>(S, D, AL) ||
|
||||
checkAttrMutualExclusion<CUDAHostAttr>(S, D, AL)) {
|
||||
return;
|
||||
}
|
||||
const auto *FD = cast<FunctionDecl>(D);
|
||||
if (!FD->getReturnType()->isVoidType() &&
|
||||
!FD->getReturnType()->getAs<AutoType>() &&
|
||||
|
@ -4513,10 +4442,6 @@ static void handleGlobalAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
}
|
||||
|
||||
static void handleDeviceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
if (checkAttrMutualExclusion<CUDAGlobalAttr>(S, D, AL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto *VD = dyn_cast<VarDecl>(D)) {
|
||||
if (VD->hasLocalStorage()) {
|
||||
S.Diag(AL.getLoc(), diag::err_cuda_nonstatic_constdev);
|
||||
|
@ -4533,11 +4458,6 @@ static void handleDeviceAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
}
|
||||
|
||||
static void handleManagedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
if (checkAttrMutualExclusion<CUDAConstantAttr>(S, D, AL) ||
|
||||
checkAttrMutualExclusion<CUDASharedAttr>(S, D, AL)) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (const auto *VD = dyn_cast<VarDecl>(D)) {
|
||||
if (VD->hasLocalStorage()) {
|
||||
S.Diag(AL.getLoc(), diag::err_cuda_nonstatic_constdev);
|
||||
|
@ -4682,7 +4602,10 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
}
|
||||
|
||||
// To check if earlier decl attributes do not conflict the newly parsed ones
|
||||
// we always add (and check) the attribute to the cannonical decl.
|
||||
// we always add (and check) the attribute to the cannonical decl. We need
|
||||
// to repeat the check for attribute mutual exclusion because we're attaching
|
||||
// all of the attributes to the canonical declaration rather than the current
|
||||
// declaration.
|
||||
D = D->getCanonicalDecl();
|
||||
if (AL.getKind() == ParsedAttr::AT_Owner) {
|
||||
if (checkAttrMutualExclusion<PointerAttr>(S, D, AL))
|
||||
|
@ -6580,6 +6503,8 @@ static void handleMipsInterruptAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
|||
return;
|
||||
}
|
||||
|
||||
// We still have to do this manually because the Interrupt attributes are
|
||||
// a bit special due to sharing their spellings across targets.
|
||||
if (checkAttrMutualExclusion<Mips16Attr>(S, D, AL))
|
||||
return;
|
||||
|
||||
|
@ -7446,9 +7371,9 @@ static void handleDestroyAttr(Sema &S, Decl *D, const ParsedAttr &A) {
|
|||
}
|
||||
|
||||
if (A.getKind() == ParsedAttr::AT_AlwaysDestroy)
|
||||
handleSimpleAttributeWithExclusions<AlwaysDestroyAttr, NoDestroyAttr>(S, D, A);
|
||||
handleSimpleAttribute<AlwaysDestroyAttr>(S, D, A);
|
||||
else
|
||||
handleSimpleAttributeWithExclusions<NoDestroyAttr, AlwaysDestroyAttr>(S, D, A);
|
||||
handleSimpleAttribute<NoDestroyAttr>(S, D, A);
|
||||
}
|
||||
|
||||
static void handleUninitializedAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
|
||||
|
@ -7740,21 +7665,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
case ParsedAttr::AT_DLLImport:
|
||||
handleDLLAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_Mips16:
|
||||
handleSimpleAttributeWithExclusions<Mips16Attr, MicroMipsAttr,
|
||||
MipsInterruptAttr>(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_MicroMips:
|
||||
handleSimpleAttributeWithExclusions<MicroMipsAttr, Mips16Attr>(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_MipsLongCall:
|
||||
handleSimpleAttributeWithExclusions<MipsLongCallAttr, MipsShortCallAttr>(
|
||||
S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_MipsShortCall:
|
||||
handleSimpleAttributeWithExclusions<MipsShortCallAttr, MipsLongCallAttr>(
|
||||
S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_AMDGPUFlatWorkGroupSize:
|
||||
handleAMDGPUFlatWorkGroupSizeAttr(S, D, AL);
|
||||
break;
|
||||
|
@ -7888,22 +7798,9 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
case ParsedAttr::AT_CUDADevice:
|
||||
handleDeviceAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_CUDAHost:
|
||||
handleSimpleAttributeWithExclusions<CUDAHostAttr, CUDAGlobalAttr>(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_HIPManaged:
|
||||
handleManagedAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_CUDADeviceBuiltinSurfaceType:
|
||||
handleSimpleAttributeWithExclusions<CUDADeviceBuiltinSurfaceTypeAttr,
|
||||
CUDADeviceBuiltinTextureTypeAttr>(S, D,
|
||||
AL);
|
||||
break;
|
||||
case ParsedAttr::AT_CUDADeviceBuiltinTextureType:
|
||||
handleSimpleAttributeWithExclusions<CUDADeviceBuiltinTextureTypeAttr,
|
||||
CUDADeviceBuiltinSurfaceTypeAttr>(S, D,
|
||||
AL);
|
||||
break;
|
||||
case ParsedAttr::AT_GNUInline:
|
||||
handleGNUInlineAttr(S, D, AL);
|
||||
break;
|
||||
|
@ -7937,12 +7834,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
case ParsedAttr::AT_Ownership:
|
||||
handleOwnershipAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_Cold:
|
||||
handleSimpleAttributeWithExclusions<ColdAttr, HotAttr>(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_Hot:
|
||||
handleSimpleAttributeWithExclusions<HotAttr, ColdAttr>(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_Naked:
|
||||
handleNakedAttr(S, D, AL);
|
||||
break;
|
||||
|
@ -7995,14 +7886,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
case ParsedAttr::AT_NSErrorDomain:
|
||||
handleNSErrorDomain(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_CFAuditedTransfer:
|
||||
handleSimpleAttributeWithExclusions<CFAuditedTransferAttr,
|
||||
CFUnknownTransferAttr>(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_CFUnknownTransfer:
|
||||
handleSimpleAttributeWithExclusions<CFUnknownTransferAttr,
|
||||
CFAuditedTransferAttr>(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_CFConsumed:
|
||||
case ParsedAttr::AT_NSConsumed:
|
||||
case ParsedAttr::AT_OSConsumed:
|
||||
|
@ -8058,15 +7941,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
case ParsedAttr::AT_Section:
|
||||
handleSectionAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_SpeculativeLoadHardening:
|
||||
handleSimpleAttributeWithExclusions<SpeculativeLoadHardeningAttr,
|
||||
NoSpeculativeLoadHardeningAttr>(S, D,
|
||||
AL);
|
||||
break;
|
||||
case ParsedAttr::AT_NoSpeculativeLoadHardening:
|
||||
handleSimpleAttributeWithExclusions<NoSpeculativeLoadHardeningAttr,
|
||||
SpeculativeLoadHardeningAttr>(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_CodeSeg:
|
||||
handleCodeSegAttr(S, D, AL);
|
||||
break;
|
||||
|
@ -8095,14 +7969,6 @@ static void ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D,
|
|||
case ParsedAttr::AT_Unused:
|
||||
handleUnusedAttr(S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_NotTailCalled:
|
||||
handleSimpleAttributeWithExclusions<NotTailCalledAttr, AlwaysInlineAttr>(
|
||||
S, D, AL);
|
||||
break;
|
||||
case ParsedAttr::AT_DisableTailCalls:
|
||||
handleSimpleAttributeWithExclusions<DisableTailCallsAttr, NakedAttr>(S, D,
|
||||
AL);
|
||||
break;
|
||||
case ParsedAttr::AT_Visibility:
|
||||
handleVisibilityAttr(S, D, AL, false);
|
||||
break;
|
||||
|
|
|
@ -332,32 +332,6 @@ CheckForIncompatibleAttributes(Sema &S,
|
|||
<< CategoryState.NumericAttr->getDiagnosticName(Policy);
|
||||
}
|
||||
}
|
||||
|
||||
// C++20 [dcl.attr.likelihood]p1 The attribute-token likely shall not appear
|
||||
// in an attribute-specifier-seq that contains the attribute-token unlikely.
|
||||
const LikelyAttr *Likely = nullptr;
|
||||
const UnlikelyAttr *Unlikely = nullptr;
|
||||
for (const auto *I : Attrs) {
|
||||
if (const auto *Attr = dyn_cast<LikelyAttr>(I)) {
|
||||
if (Unlikely) {
|
||||
S.Diag(Attr->getLocation(), diag::err_attributes_are_not_compatible)
|
||||
<< Attr << Unlikely << Attr->getRange();
|
||||
S.Diag(Unlikely->getLocation(), diag::note_conflicting_attribute)
|
||||
<< Unlikely->getRange();
|
||||
return;
|
||||
}
|
||||
Likely = Attr;
|
||||
} else if (const auto *Attr = dyn_cast<UnlikelyAttr>(I)) {
|
||||
if (Likely) {
|
||||
S.Diag(Attr->getLocation(), diag::err_attributes_are_not_compatible)
|
||||
<< Attr << Likely << Attr->getRange();
|
||||
S.Diag(Likely->getLocation(), diag::note_conflicting_attribute)
|
||||
<< Likely->getRange();
|
||||
return;
|
||||
}
|
||||
Unlikely = Attr;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static Attr *handleOpenCLUnrollHint(Sema &S, Stmt *St, const ParsedAttr &A,
|
||||
|
|
|
@ -10,3 +10,9 @@ int qux() __attribute__((__hot__)) __attribute__((__cold__)); // expected-error{
|
|||
// expected-note{{conflicting attribute is here}}
|
||||
int baz() __attribute__((__cold__)) __attribute__((__hot__)); // expected-error{{'__hot__' and 'cold' attributes are not compatible}} \
|
||||
// expected-note{{conflicting attribute is here}}
|
||||
|
||||
__attribute__((cold)) void test1(void); // expected-note{{conflicting attribute is here}}
|
||||
__attribute__((hot)) void test1(void); // expected-error{{'hot' and 'cold' attributes are not compatible}}
|
||||
|
||||
__attribute__((hot)) void test2(void); // expected-note{{conflicting attribute is here}}
|
||||
__attribute__((cold)) void test2(void); // expected-error{{'cold' and 'hot' attributes are not compatible}}
|
||||
|
|
|
@ -11,3 +11,9 @@ void __attribute__((naked,disable_tail_calls)) foo2(int a) { // expected-error {
|
|||
int g0 __attribute__((disable_tail_calls)); // expected-warning {{'disable_tail_calls' attribute only applies to functions and Objective-C methods}}
|
||||
|
||||
int foo3(int a) __attribute__((disable_tail_calls("abc"))); // expected-error {{'disable_tail_calls' attribute takes no arguments}}
|
||||
|
||||
__attribute__((naked)) void foo4(void); // expected-note {{conflicting attribute is here}}
|
||||
__attribute__((disable_tail_calls)) void foo4(void); // expected-error {{'disable_tail_calls' and 'naked' attributes are not compatible}}
|
||||
|
||||
__attribute__((disable_tail_calls)) void foo5(void); // expected-note {{conflicting attribute is here}}
|
||||
__attribute__((naked)) void foo5(void); // expected-error {{'naked' and 'disable_tail_calls' attributes are not compatible}}
|
||||
|
|
|
@ -6,13 +6,12 @@ int var2 __attribute__((internal_linkage,common)); // expected-error{{'common' a
|
|||
int var3 __attribute__((common,internal_linkage)); // expected-error{{'internal_linkage' and 'common' attributes are not compatible}} \
|
||||
// expected-note{{conflicting attribute is here}}
|
||||
|
||||
int var4 __attribute__((common)); // expected-error{{'common' and 'internal_linkage' attributes are not compatible}} \
|
||||
// expected-note{{previous definition is here}}
|
||||
int var4 __attribute__((internal_linkage)); // expected-note{{conflicting attribute is here}} \
|
||||
// expected-error{{'internal_linkage' attribute does not appear on the first declaration of 'var4'}}
|
||||
int var4 __attribute__((common)); // expected-note{{previous definition is here}} expected-note{{conflicting attribute is here}}
|
||||
int var4 __attribute__((internal_linkage)); // expected-error{{'internal_linkage' and 'common' attributes are not compatible}} \
|
||||
// expected-error{{'internal_linkage' attribute does not appear on the first declaration of 'var4'}}
|
||||
|
||||
int var5 __attribute__((internal_linkage)); // expected-error{{'internal_linkage' and 'common' attributes are not compatible}}
|
||||
int var5 __attribute__((common)); // expected-note{{conflicting attribute is here}}
|
||||
int var5 __attribute__((internal_linkage)); // expected-note{{conflicting attribute is here}}
|
||||
int var5 __attribute__((common)); // expected-error{{'common' and 'internal_linkage' attributes are not compatible}}
|
||||
|
||||
__attribute__((internal_linkage)) int f() {}
|
||||
struct __attribute__((internal_linkage)) S { // expected-warning{{'internal_linkage' attribute only applies to variables, functions, and classes}}
|
||||
|
|
|
@ -22,10 +22,9 @@ void f4() __attribute__((no_speculative_load_hardening, speculative_load_hardeni
|
|||
void f5() __attribute__((speculative_load_hardening, no_speculative_load_hardening)); // expected-error {{attributes are not compatible}}
|
||||
// expected-note@-1 {{conflicting attribute is here}}
|
||||
|
||||
void f6() __attribute__((no_speculative_load_hardening));
|
||||
void f6() __attribute__((no_speculative_load_hardening)); // expected-note {{conflicting attribute is here}}
|
||||
|
||||
void f6() __attribute__((speculative_load_hardening)); // expected-error@-2 {{'no_speculative_load_hardening' and 'speculative_load_hardening' attributes are not compatible}}
|
||||
// expected-note@-1 {{conflicting attribute is here}}
|
||||
void f6() __attribute__((speculative_load_hardening)); // expected-error {{'speculative_load_hardening' and 'no_speculative_load_hardening' attributes are not compatible}}
|
||||
|
||||
int ci [[clang::speculative_load_hardening]]; // expected-error {{'speculative_load_hardening' attribute only applies to functions}}
|
||||
|
||||
|
@ -51,8 +50,8 @@ struct CA {
|
|||
// expected-note@-1 {{conflicting attribute is here}}
|
||||
|
||||
[[clang::speculative_load_hardening]]
|
||||
void cf6();
|
||||
void cf6(); // expected-note@-1 {{conflicting attribute is here}}
|
||||
|
||||
[[clang::no_speculative_load_hardening]]
|
||||
void cf6(); // expected-error@-4 {{'speculative_load_hardening' and 'no_speculative_load_hardening' attributes are not compatible}} \
|
||||
// expected-note@-1 {{conflicting attribute is here}}
|
||||
void cf6(); // expected-error@-1 {{'no_speculative_load_hardening' and 'speculative_load_hardening' attributes are not compatible}} \
|
||||
|
||||
|
|
|
@ -3627,6 +3627,114 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
|
|||
}
|
||||
}
|
||||
|
||||
// Generates the mutual exclusion checks. The checks for parsed attributes are
|
||||
// written into OS and the checks for merging declaration attributes are
|
||||
// written into MergeOS.
|
||||
static void GenerateMutualExclusionsChecks(const Record &Attr,
|
||||
const RecordKeeper &Records,
|
||||
raw_ostream &OS,
|
||||
raw_ostream &MergeOS) {
|
||||
// Find all of the definitions that inherit from MutualExclusions and include
|
||||
// the given attribute in the list of exclusions to generate the
|
||||
// diagMutualExclusion() check.
|
||||
std::vector<Record *> ExclusionsList =
|
||||
Records.getAllDerivedDefinitions("MutualExclusions");
|
||||
|
||||
// We don't do any of this magic for type attributes yet.
|
||||
if (Attr.isSubClassOf("TypeAttr"))
|
||||
return;
|
||||
|
||||
// This means the attribute is either a statement attribute or a decl
|
||||
// attribute, find out which.
|
||||
bool CurAttrIsStmtAttr =
|
||||
Attr.isSubClassOf("StmtAttr") || Attr.isSubClassOf("DeclOrStmtAttr");
|
||||
|
||||
std::vector<std::string> DeclAttrs, StmtAttrs;
|
||||
|
||||
for (const Record *Exclusion : ExclusionsList) {
|
||||
std::vector<Record *> MutuallyExclusiveAttrs =
|
||||
Exclusion->getValueAsListOfDefs("Exclusions");
|
||||
auto IsCurAttr = [Attr](const Record *R) {
|
||||
return R->getName() == Attr.getName();
|
||||
};
|
||||
if (llvm::any_of(MutuallyExclusiveAttrs, IsCurAttr)) {
|
||||
// This list of exclusions includes the attribute we're looking for, so
|
||||
// add the exclusive attributes to the proper list for checking.
|
||||
for (const Record *AttrToExclude : MutuallyExclusiveAttrs) {
|
||||
if (IsCurAttr(AttrToExclude))
|
||||
continue;
|
||||
|
||||
if (CurAttrIsStmtAttr)
|
||||
StmtAttrs.push_back((AttrToExclude->getName() + "Attr").str());
|
||||
else
|
||||
DeclAttrs.push_back((AttrToExclude->getName() + "Attr").str());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// If we discovered any decl or stmt attributes to test for, generate the
|
||||
// predicates for them now.
|
||||
if (!DeclAttrs.empty()) {
|
||||
// Generate the ParsedAttrInfo subclass logic for declarations.
|
||||
OS << " bool diagMutualExclusion(Sema &S, const ParsedAttr &AL, "
|
||||
<< "const Decl *D) const {\n";
|
||||
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";
|
||||
OS << " S.Diag(A->getLocation(), diag::note_conflicting_attribute);";
|
||||
OS << " \nreturn false;\n";
|
||||
OS << " }\n";
|
||||
}
|
||||
OS << " return true;\n";
|
||||
OS << " }\n\n";
|
||||
|
||||
// Also generate the declaration attribute merging logic if the current
|
||||
// attribute is one that can be inheritted on a declaration. It is assumed
|
||||
// this code will be executed in the context of a function with parameters:
|
||||
// Sema &S, Decl *D, Attr *A and that returns a bool (false on diagnostic,
|
||||
// true on success).
|
||||
if (Attr.isSubClassOf("InheritableAttr")) {
|
||||
MergeOS << " if (const auto *Second = dyn_cast<"
|
||||
<< (Attr.getName() + "Attr").str() << ">(A)) {\n";
|
||||
for (const std::string &A : DeclAttrs) {
|
||||
MergeOS << " if (const auto *First = D->getAttr<" << A << ">()) {\n";
|
||||
MergeOS << " S.Diag(First->getLocation(), "
|
||||
<< "diag::err_attributes_are_not_compatible) << First << "
|
||||
<< "Second;\n";
|
||||
MergeOS << " S.Diag(Second->getLocation(), "
|
||||
<< "diag::note_conflicting_attribute);\n";
|
||||
MergeOS << " return false;\n";
|
||||
MergeOS << " }\n";
|
||||
}
|
||||
MergeOS << " return true;\n";
|
||||
MergeOS << " }\n";
|
||||
}
|
||||
}
|
||||
if (!StmtAttrs.empty()) {
|
||||
// Generate the ParsedAttrInfo subclass logic for statements.
|
||||
OS << " bool diagMutualExclusion(Sema &S, const ParsedAttr &AL, "
|
||||
<< "const Stmt *St) const {\n";
|
||||
OS << " if (const auto *AS = dyn_cast<AttributedStmt>(St)) {\n";
|
||||
OS << " const ArrayRef<const Attr *> &Attrs = AS->getAttrs();\n";
|
||||
for (const std::string &A : StmtAttrs) {
|
||||
OS << " auto Iter" << A << " = llvm::find_if(Attrs, [](const Attr "
|
||||
<< "*A) { return isa<" << A << ">(A); });\n";
|
||||
OS << " if (Iter" << A << " != Attrs.end()) {\n";
|
||||
OS << " S.Diag(AL.getLoc(), "
|
||||
<< "diag::err_attributes_are_not_compatible) << AL << *Iter" << A
|
||||
<< ";\n";
|
||||
OS << " S.Diag((*Iter" << A << ")->getLocation(), "
|
||||
<< "diag::note_conflicting_attribute);\n";
|
||||
OS << " return false;\n";
|
||||
OS << " }\n";
|
||||
}
|
||||
OS << " }\n";
|
||||
OS << " return true;\n";
|
||||
OS << " }\n\n";
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
emitAttributeMatchRules(PragmaClangAttributeSupport &PragmaAttributeSupport,
|
||||
raw_ostream &OS) {
|
||||
|
@ -3775,6 +3883,7 @@ static bool IsKnownToGCC(const Record &Attr) {
|
|||
void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
|
||||
emitSourceFileHeader("Parsed attribute helpers", OS);
|
||||
|
||||
OS << "#if !defined(WANT_MERGE_LOGIC)\n";
|
||||
PragmaClangAttributeSupport &PragmaAttributeSupport =
|
||||
getPragmaAttributeSupport(Records);
|
||||
|
||||
|
@ -3795,6 +3904,12 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
|
|||
GenerateCustomAppertainsTo(*Subject, OS);
|
||||
}
|
||||
|
||||
// This stream is used to collect all of the declaration attribute merging
|
||||
// logic for performing mutual exclusion checks. This gets emitted at the
|
||||
// end of the file in a helper function of its own.
|
||||
std::string DeclMergeChecks;
|
||||
raw_string_ostream MergeOS(DeclMergeChecks);
|
||||
|
||||
// Generate a ParsedAttrInfo struct for each of the attributes.
|
||||
for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) {
|
||||
// TODO: If the attribute's kind appears in the list of duplicates, that is
|
||||
|
@ -3848,6 +3963,7 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
|
|||
OS << " Spellings = " << I->first << "Spellings;\n";
|
||||
OS << " }\n";
|
||||
GenerateAppertainsTo(Attr, OS);
|
||||
GenerateMutualExclusionsChecks(Attr, Records, OS, MergeOS);
|
||||
GenerateLangOptRequirements(Attr, OS);
|
||||
GenerateTargetRequirements(Attr, Dupes, OS);
|
||||
GenerateSpellingIndexToSemanticSpelling(Attr, OS);
|
||||
|
@ -3867,6 +3983,17 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
|
|||
|
||||
// Generate the attribute match rules.
|
||||
emitAttributeMatchRules(PragmaAttributeSupport, OS);
|
||||
|
||||
OS << "#else // WANT_MERGE_LOGIC\n\n";
|
||||
|
||||
// Write out the declaration merging check logic.
|
||||
OS << "static bool DiagnoseMutualExclusions(Sema &S, const NamedDecl *D, "
|
||||
<< "const Attr *A) {\n";
|
||||
OS << MergeOS.str();
|
||||
OS << " return true;\n";
|
||||
OS << "}\n\n";
|
||||
|
||||
OS << "#endif // WANT_MERGE_LOGIC\n";
|
||||
}
|
||||
|
||||
// Emits the kind list of parsed attributes
|
||||
|
|
Loading…
Reference in New Issue