-
Notifications
You must be signed in to change notification settings - Fork 769
[SYCL] Correct the tablegen for 8000 checking mutually exclusive stmt attrs #3519
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -95,12 +95,6 @@ struct ParsedAttrInfo { | |
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 { | ||
|
@@ -615,7 +609,12 @@ class ParsedAttr final | |
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; | ||
// This function stub exists for parity with the declaration checking code so | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I do not like this design but I could not think of a more elegant solution. If you have better ideas that don't result in code duplication in |
||
// that checkCommonAttributeFeatures() can work generically on declarations | ||
// or statements. | ||
bool diagnoseMutualExclusion(class Sema &S, const Stmt *St) const { | ||
return true; | ||
} | ||
bool appliesToDecl(const Decl *D, attr::SubjectMatchRule MatchRule) const; | ||
void getMatchRules(const LangOptions &LangOpts, | ||
SmallVectorImpl<std::pair<attr::SubjectMatchRule, bool>> | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -3653,7 +3653,8 @@ static void GenerateAppertainsTo(const Record &Attr, raw_ostream &OS) { | |
static void GenerateMutualExclusionsChecks(const Record &Attr, | ||
const RecordKeeper &Records, | ||
raw_ostream &OS, | ||
raw_ostream &MergeOS) { | ||
raw_ostream &MergeDeclOS, | ||
raw_ostream &MergeStmtOS) { | ||
Comment on lines
-3656
to
+3657
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I'm also not in love with this function generating code into three separate streams, but I couldn't think of a better approach that avoids walking the entire list of records from Attr.td multiple times (which slows down compile speeds because there are a fair amount of records in that file these days). |
||
// Find all of the definitions that inherit from MutualExclusions and include | ||
// the given attribute in the list of exclusions to generate the | ||
// diagMutualExclusion() check. | ||
|
@@ -3717,43 +3718,59 @@ static void GenerateMutualExclusionsChecks(const Record &Attr, | |
// 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"; | ||
MergeDeclOS << " 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"; | ||
MergeDeclOS << " if (const auto *First = D->getAttr<" << A | ||
<< ">()) {\n"; | ||
MergeDeclOS << " S.Diag(First->getLocation(), " | ||
<< "diag::err_attributes_are_not_compatible) << First << " | ||
<< "Second;\n"; | ||
MergeDeclOS << " S.Diag(Second->getLocation(), " | ||
<< "diag::note_conflicting_attribute);\n"; | ||
MergeDeclOS << " return false;\n"; | ||
MergeDeclOS << " }\n"; | ||
} | ||
MergeOS << " return true;\n"; | ||
MergeOS << " }\n"; | ||
MergeDeclOS << " return true;\n"; | ||
MergeDeclOS << " }\n"; | ||
} | ||
} | ||
|
||
// Statement attributes are a bit different from declarations. With | ||
// declarations, each attribute is added to the declaration as it is | ||
// processed, and so you can look on the Decl * itself to see if there is a | ||
// conflicting attribute. Statement attributes are processed as a group | ||
// because AttributedStmt needs to tail-allocate all of the attribute nodes | ||
// at once. This means we cannot check whether the statement already contains | ||
// an attribute to check for the conflict. Instead, we need to check whether | ||
// the given list of semantic attributes contain any conflicts. It is assumed | ||
// this code will be executed in the context of a function with parameters: | ||
// Sema &S, const SmallVectorImpl<const Attr *> &C. The code will be within a | ||
// loop which loops over the container C with a loop variable named A to | ||
// represent the current attribute to check for conflicts. | ||
// | ||
// FIXME: it would be nice not to walk over the list of potential attributes | ||
// to apply to the statement more than once, but statements typically don't | ||
// have long lists of attributes on them, so re-walking the list should not | ||
// be an expensive operation. | ||
if (!StmtAttrs.empty()) { | ||
// Generate the ParsedAttrInfo subclass logic for statements. | ||
OS << " bool diagMutualExclusion(Sema &S, const ParsedAttr &AL, " | ||
<< "const Stmt *St) const override {\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"; | ||
MergeStmtOS << " if (const auto *Second = dyn_cast<" | ||
<< (Attr.getName() + "Attr").str() << ">(A)) {\n"; | ||
MergeStmtOS << " auto Iter = llvm::find_if(C, [](const Attr *Check) " | ||
<< "{ return isa<"; | ||
interleave( | ||
StmtAttrs, [&](const std::string &Name) { MergeStmtOS << Name; }, | ||
[&] { MergeStmtOS << ", "; }); | ||
MergeStmtOS << ">(Check); });\n"; | ||
MergeStmtOS << " if (Iter != C.end()) {\n"; | ||
MergeStmtOS << " S.Diag((*Iter)->getLocation(), " | ||
<< "diag::err_attributes_are_not_compatible) << *Iter << " | ||
<< "Second;\n"; | ||
MergeStmtOS << " S.Diag(Second->getLocation(), " | ||
<< "diag::note_conflicting_attribute);\n"; | ||
MergeStmtOS << " return false;\n"; | ||
MergeStmtOS << " }\n"; | ||
MergeStmtOS << " }\n"; | ||
} | ||
} | ||
|
||
|
@@ -3905,7 +3922,8 @@ 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"; | ||
OS << "#if !defined(WANT_DECL_MERGE_LOGIC) && " | ||
<< "!defined(WANT_STMT_MERGE_LOGIC)\n"; | ||
PragmaClangAttributeSupport &PragmaAttributeSupport = | ||
getPragmaAttributeSupport(Records); | ||
|
||
|
@@ -3929,8 +3947,8 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &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); | ||
std::string DeclMergeChecks, StmtMergeChecks; | ||
raw_string_ostream MergeDeclOS(DeclMergeChecks), MergeStmtOS(StmtMergeChecks); | ||
|
||
// Generate a ParsedAttrInfo struct for each of the attributes. | ||
for (auto I = Attrs.begin(), E = Attrs.end(); I != E; ++I) { | ||
|
@@ -3987,7 +4005,7 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { | |
OS << " Spellings = " << I->first << "Spellings;\n"; | ||
OS << " }\n"; | ||
GenerateAppertainsTo(Attr, OS); | ||
GenerateMutualExclusionsChecks(Attr, Records, OS, MergeOS); | ||
GenerateMutualExclusionsChecks(Attr, Records, OS, MergeDeclOS, MergeStmtOS); | ||
GenerateLangOptRequirements(Attr, OS); | ||
GenerateTargetRequirements(Attr, Dupes, OS); | ||
GenerateSpellingIndexToSemanticSpelling(Attr, OS); | ||
|
@@ -4008,16 +4026,27 @@ void EmitClangAttrParsedAttrImpl(RecordKeeper &Records, raw_ostream &OS) { | |
// Generate the attribute match rules. | ||
emitAttributeMatchRules(PragmaAttributeSupport, OS); | ||
|
||
OS << "#else // WANT_MERGE_LOGIC\n\n"; | ||
OS << "#elif defined(WANT_DECL_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 << MergeDeclOS.str(); | ||
OS << " return true;\n"; | ||
OS << "}\n\n"; | ||
|
||
OS << "#endif // WANT_MERGE_LOGIC\n"; | ||
OS << "#elif defined(WANT_STMT_MERGE_LOGIC)\n\n"; | ||
|
||
// Write out the statement merging check logic. | ||
OS << "static bool DiagnoseMutualExclusions(Sema &S, " | ||
<< "const SmallVectorImpl<const Attr *> &C) {\n"; | ||
OS << " for (const Attr *A : C) {\n"; | ||
OS << MergeStmtOS.str(); | ||
OS << " }\n"; | ||
OS << " return true;\n"; | ||
OS << "}\n\n"; | ||
|
||
OS << "#endif\n"; | ||
} | ||
|
||
// Emits the kind list of parsed attributes | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
NB: this is done for completeness in this review but will be in conflict with #3512. Assuming that one lands first, I'll correct the merge conflict in this review.