@@ -3653,7 +3653,8 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) {
3653
3653
static void GenerateMutualExclusionsChecks (const Record &Attr,
3654
3654
const RecordKeeper &Records,
3655
3655
raw_ostream &OS,
3656
- raw_ostream &MergeOS) {
3656
+ raw_ostream &MergeDeclOS,
3657
+ raw_ostream &MergeStmtOS) {
3657
3658
// Find all of the definitions that inherit from MutualExclusions and include
3658
3659
// the given attribute in the list of exclusions to generate the
3659
3660
// diagMutualExclusion() check.
@@ -3717,43 +3718,59 @@ static void GenerateMutualExclusionsChecks(const Record &Attr,
3717
3718
// Sema &S, Decl *D, Attr *A and that returns a bool (false on diagnostic,
3718
3719
// true on success).
3719
3720
if (Attr.isSubClassOf (" InheritableAttr" )) {
3720
- MergeOS << " if (const auto *Second = dyn_cast<"
3721
- << (Attr.getName () + " Attr" ).str () << " >(A)) {\n " ;
3721
+ MergeDeclOS << " if (const auto *Second = dyn_cast<"
3722
+ << (Attr.getName () + " Attr" ).str () << " >(A)) {\n " ;
3722
3723
for (const std::string &A : DeclAttrs) {
3723
- MergeOS << " if (const auto *First = D->getAttr<" << A << " >()) {\n " ;
3724
- MergeOS << " S.Diag(First->getLocation(), "
3725
- << " diag::err_attributes_are_not_compatible) << First << "
3726
- << " Second;\n " ;
3727
- MergeOS << " S.Diag(Second->getLocation(), "
3728
- << " diag::note_conflicting_attribute);\n " ;
3729
- MergeOS << " return false;\n " ;
3730
- MergeOS << " }\n " ;
3724
+ MergeDeclOS << " if (const auto *First = D->getAttr<" << A
3725
+ << " >()) {\n " ;
3726
+ MergeDeclOS << " S.Diag(First->getLocation(), "
3727
+ << " diag::err_attributes_are_not_compatible) << First << "
3728
+ << " Second;\n " ;
3729
+ MergeDeclOS << " S.Diag(Second->getLocation(), "
3730
+ << " diag::note_conflicting_attribute);\n " ;
3731
+ MergeDeclOS << " return false;\n " ;
3732
+ MergeDeclOS << " }\n " ;
3731
3733
}
3732
- MergeOS << " return true;\n " ;
3733
- MergeOS << " }\n " ;
3734
+ MergeDeclOS << " return true;\n " ;
3735
+ MergeDeclOS << " }\n " ;
3734
3736
}
3735
3737
}
3738
+
3739
+ // Statement attributes are a bit different from declarations. With
3740
+ // declarations, each attribute is added to the declaration as it is
3741
+ // processed, and so you can look on the Decl * itself to see if there is a
3742
+ // conflicting attribute. Statement attributes are processed as a group
3743
+ // because AttributedStmt needs to tail-allocate all of the attribute nodes
3744
+ // at once. This means we cannot check whether the statement already contains
3745
+ // an attribute to check for the conflict. Instead, we need to check whether
3746
+ // the given list of semantic attributes contain any conflicts. It is assumed
3747
+ // this code will be executed in the context of a function with parameters:
3748
+ // Sema &S, const SmallVectorImpl<const Attr *> &C. The code will be within a
3749
+ // loop which loops over the container C with a loop variable named A to
3750
+ // represent the current attribute to check for conflicts.
3751
+ //
3752
+ // FIXME: it would be nice not to walk over the list of potential attributes
3753
+ // to apply to the statement more than once, but statements typically don't
3754
+ // have long lists of attributes on them, so re-walking the list should not
3755
+ // be an expensive operation.
3736
3756
if (!StmtAttrs.empty ()) {
3737
- // Generate the ParsedAttrInfo subclass logic for statements.
3738
- OS << " bool diagMutualExclusion(Sema &S, const ParsedAttr &AL, "
3739
- << " const Stmt *St) const override {\n " ;
3740
- OS << " if (const auto *AS = dyn_cast<AttributedStmt>(St)) {\n " ;
3741
- OS << " const ArrayRef<const Attr *> &Attrs = AS->getAttrs();\n " ;
3742
- for (const std::string &A : StmtAttrs) {
3743
- OS << " auto Iter" << A << " = llvm::find_if(Attrs, [](const Attr "
3744
- << " *A) { return isa<" << A << " >(A); });\n " ;
3745
- OS << " if (Iter" << A << " != Attrs.end()) {\n " ;
3746
- OS << " S.Diag(AL.getLoc(), "
3747
- << " diag::err_attributes_are_not_compatible) << AL << *Iter" << A
3748
- << " ;\n " ;
3749
- OS << " S.Diag((*Iter" << A << " )->getLocation(), "
3750
- << " diag::note_conflicting_attribute);\n " ;
3751
- OS << " return false;\n " ;
3752
- OS << " }\n " ;
3753
- }
3754
- OS << " }\n " ;
3755
- OS << " return true;\n " ;
3756
- OS << " }\n\n " ;
3757
+ MergeStmtOS << " if (const auto *Second = dyn_cast<"
3758
+ << (Attr.getName () + " Attr" ).str () << " >(A)) {\n " ;
3759
+ MergeStmtOS << " auto Iter = llvm::find_if(C, [](const Attr *Check) "
3760
+ << " { return isa<" ;
3761
+ interleave (
3762
+ StmtAttrs, [&](const std::string &Name) { MergeStmtOS << Name; },
3763
+ [&] { MergeStmtOS << " , " ; });
3764
+ MergeStmtOS << " >(Check); });\n " ;
3765
+ MergeStmtOS << " if (Iter != C.end()) {\n " ;
3766
+ MergeStmtOS << " S.Diag((*Iter)->getLocation(), "
3767
+ << " diag::err_attributes_are_not_compatible) << *Iter << "
3768
+ << " Second;\n " ;
3769
+ MergeStmtOS << " S.Diag(Second->getLocation(), "
3770
+ << " diag::note_conflicting_attribute);\n " ;
3771
+ MergeStmtOS << " return false;\n " ;
3772
+ MergeStmtOS << " }\n " ;
3773
+ MergeStmtOS << " }\n " ;
3757
3774
}
3758
3775
}
3759
3776
@@ -3905,7 +3922,8 @@ static bool IsKnownToGCC(const Record &Attr) {
3905
3922
void EmitClangAttrParsedAttrImpl (RecordKeeper &Records, raw_ostream &OS) {
3906
3923
emitSourceFileHeader (" Parsed attribute helpers" , OS);
3907
3924
3908
- OS << " #if !defined(WANT_MERGE_LOGIC)\n " ;
3925
+ OS << " #if !defined(WANT_DECL_MERGE_LOGIC) && "
3926
+ << " !defined(WANT_STMT_MERGE_LOGIC)\n " ;
3909
3927
PragmaClangAttributeSupport &PragmaAttributeSupport =
3910
3928
getPragmaAttributeSupport (Records);
3911
3929
@@ -3929,8 +3947,8 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
3929
3947
// This stream is used to collect all of the declaration attribute merging
3930
3948
// logic for performing mutual exclusion checks. This gets emitted at the
3931
3949
// end of the file in a helper function of its own.
3932
- std::string DeclMergeChecks;
3933
- raw_string_ostream MergeOS (DeclMergeChecks);
3950
+ std::string DeclMergeChecks, StmtMergeChecks ;
3951
+ raw_string_ostream MergeDeclOS (DeclMergeChecks), MergeStmtOS (StmtMergeChecks );
3934
3952
3935
3953
// Generate a ParsedAttrInfo struct for each of the attributes.
3936
3954
for (auto I = Attrs.begin (), E = Attrs.end (); I != E; ++I) {
@@ -3987,7 +4005,7 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
3987
4005
OS << " Spellings = " << I->first << " Spellings;\n " ;
3988
4006
OS << " }\n " ;
3989
4007
GenerateAppertainsTo (Attr, OS);
3990
- GenerateMutualExclusionsChecks (Attr, Records, OS, MergeOS );
4008
+ GenerateMutualExclusionsChecks (Attr, Records, OS, MergeDeclOS, MergeStmtOS );
3991
4009
GenerateLangOptRequirements (Attr, OS);
3992
4010
GenerateTargetRequirements (Attr, Dupes, OS);
3993
4011
GenerateSpellingIndexToSemanticSpelling (Attr, OS);
@@ -4008,16 +4026,27 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) {
4008
4026
// Generate the attribute match rules.
4009
4027
emitAttributeMatchRules (PragmaAttributeSupport, OS);
4010
4028
4011
- OS << " #else // WANT_MERGE_LOGIC \n\n " ;
4029
+ OS << " #elif defined(WANT_DECL_MERGE_LOGIC) \n\n " ;
4012
4030
4013
4031
// Write out the declaration merging check logic.
4014
4032
OS << " static bool DiagnoseMutualExclusions(Sema &S, const NamedDecl *D, "
4015
4033
<< " const Attr *A) {\n " ;
4016
- OS << MergeOS .str ();
4034
+ OS << MergeDeclOS .str ();
4017
4035
OS << " return true;\n " ;
4018
4036
OS << " }\n\n " ;
4019
4037
4020
- OS << " #endif // WANT_MERGE_LOGIC\n " ;
4038
+ OS << " #elif defined(WANT_STMT_MERGE_LOGIC)\n\n " ;
4039
+
4040
+ // Write out the statement merging check logic.
4041
+ OS << " static bool DiagnoseMutualExclusions(Sema &S, "
4042
+ << " const SmallVectorImpl<const Attr *> &C) {\n " ;
4043
+ OS << " for (const Attr *A : C) {\n " ;
4044
+ OS << MergeStmtOS.str ();
4045
+ OS << " }\n " ;
4046
+ OS << " return true;\n " ;
4047
+ OS << " }\n\n " ;
4048
+
4049
+ OS << " #endif\n " ;
4021
4050
}
4022
4051
4023
4052
// Emits the kind list of parsed attributes
0 commit comments