[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
Dan Liew via cfe-commits
cfe-commits at lists.llvm.org
Sat Apr 13 22:39:59 PDT 2024
================
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string &VarName,
OS << " }\n";
}
+enum class LateAttrParseKind {
+ LateAttrParsingNever = 0,
+ LateAttrParsingAlways = 1,
+ LateAttrParsingExperimentalOnly = 2
+};
+
+static LateAttrParseKind getLateAttrParseKind(const Record *Attr) {
+ // This function basically does
+ // `Attr->getValueAsDef("LateParsed")->getValueAsInt("Mode")` but does
+ // a bunch of sanity checking to ensure that
+ // `LateAttrParseMode` in `Attr.td` is in sync with the `LateAttrParseKind`
+ // enum in this source file.
+
+ const char *LateParsedStr = "LateParsed";
+ auto *LAPK = Attr->getValueAsDef(LateParsedStr);
+
+ // Typecheck the `LateParsed` field.
+ SmallVector<Record *, 1> SuperClasses;
+ LAPK->getDirectSuperClasses(SuperClasses);
+ if (SuperClasses.size() != 1) {
+ PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) +
+ "`should only have one super class");
+ }
+ const char *LateAttrParseKindStr = "LateAttrParseKind";
+ if (SuperClasses[0]->getName().compare(LateAttrParseKindStr) != 0) {
+ PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) +
+ "`should only have type `" +
+ llvm::Twine(LateAttrParseKindStr) +
+ "` but found type `" +
+ SuperClasses[0]->getName() + "`");
+ }
+
+ // Get Kind and verify the enum name matches the name in `Attr.td`.
+ const char *KindFieldStr = "Kind";
+ unsigned Kind = LAPK->getValueAsInt(KindFieldStr);
+ switch (LateAttrParseKind(Kind)) {
+#define CASE(X) \
+ case LateAttrParseKind::X: \
+ if (LAPK->getName().compare(#X) != 0) { \
+ PrintFatalError(Attr, \
+ "Field `" + llvm::Twine(LateParsedStr) + "` set to `" + \
+ LAPK->getName() + \
+ "` but this converts to `LateAttrParseKind::" + \
+ llvm::Twine(#X) + "`"); \
+ } \
+ return LateAttrParseKind::X;
+
+ CASE(LateAttrParsingNever)
+ CASE(LateAttrParsingAlways)
+ CASE(LateAttrParsingExperimentalOnly)
+#undef CASE
+ }
+
+ // The Kind value is completely invalid
+ auto KindValueStr = llvm::utostr(Kind);
+ PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + "` set to `" +
+ LAPK->getName() + "` has unexpected `" +
+ llvm::Twine(KindFieldStr) + "` value of " +
+ KindValueStr);
+}
+
// Emits the LateParsed property for attributes.
-static void emitClangAttrLateParsedList(RecordKeeper &Records, raw_ostream &OS) {
- OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n";
- std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
+static void emitClangAttrLateParsedListImpl(RecordKeeper &Records,
+ raw_ostream &OS,
+ LateAttrParseKind LateParseMode) {
+ std::vector<Record *> Attrs = Records.getAllDerivedDefinitions("Attr");
for (const auto *Attr : Attrs) {
- bool LateParsed = Attr->getValueAsBit("LateParsed");
+ auto LateParsed = getLateAttrParseKind(Attr);
- if (LateParsed) {
- std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr);
+ if (LateParsed != LateParseMode)
+ continue;
- // FIXME: Handle non-GNU attributes
- for (const auto &I : Spellings) {
- if (I.variety() != "GNU")
- continue;
- OS << ".Case(\"" << I.name() << "\", " << LateParsed << ")\n";
- }
+ std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(*Attr);
+
+ // FIXME: Handle non-GNU attributes
+ for (const auto &I : Spellings) {
+ if (I.variety() != "GNU")
+ continue;
+ OS << ".Case(\"" << I.name() << "\", 1)\n";
}
}
+}
+
+static void emitClangAttrLateParsedList(RecordKeeper &Records,
+ raw_ostream &OS) {
+ OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n";
+ emitClangAttrLateParsedListImpl(Records, OS,
+ LateAttrParseKind::LateAttrParsingAlways);
OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n";
}
----------------
delcypher wrote:
By "inling" I assume you mean duplicating `emitClangAttrLateParsedListImpl` into `emitClangAttrLateParsedList` and `emitClangAttrLateParsedExperimentalList`. I've deliberately avoided doing that to avoid duplicating code. Another reason for avoiding the duplication is that the code has a `FIXME` and its probably best to avoid duplicating that if it's not necessary.
https://github.com/llvm/llvm-project/pull/88596
More information about the cfe-commits
mailing list