[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
Fri Apr 12 18:22:37 PDT 2024
https://github.com/delcypher updated https://github.com/llvm/llvm-project/pull/88596
>From 554287a724361a510389d7f34f9b57cf434b9657 Mon Sep 17 00:00:00 2001
From: Dan Liew <dan at su-root.co.uk>
Date: Fri, 12 Apr 2024 17:36:19 -0700
Subject: [PATCH] [Attributes] Support Attributes being declared as only
supporting late parsing when passing an experimental feature flag
This patch changes the `LateParsed` field of `Attr` in `Attr.td` to be
an instantiation of the new `LateAttrParseKind` class. The instation can be one of the following:
* `LateAttrParsingNever` - Corresponds with the false value of `LateParsed` prior to this patch (the default for an attribute).
* `LateAttrParsingAlways` - Corresponds with the true value of `LateParsed` prior to this patch.
* `LateAttrParsingExperimentalOnly` - A new mode described below.
`LateAttrParsingExperimentalOnly` means that the attribute will be late
parsed if the new the `ExperimentalLateParseAttributes` language option (also introduced in
this patch) is enabled and will **not** be late parsed if the language
option is disabled.
The new `ExperimentalLateParseAttributes` language option is controlled
by a new driver and frontend flag
(`-fexperimental-late-parse-attributes`). A driver test is included to
check that the driver passes the flag to CC1.
In this patch the `LateAttrParsingExperimentalOnly` is not adopted by
any attribute so `-fexperimental-late-pase-attributes` and the
corresponding language option currently have no effect on compilation.
This is why this patch does not include any test cases that test
`LateAttrParsingExperimentalOnly`'s behavior.
The motivation for this patch is to be able to late parse the new
`counted_by` attribute but only do so when a feature flag is passed.
This was discussed during the [bounds-safety RFC](https://discourse.llvm.org/t/rfc-enforcing-bounds-safety-in-c-fbounds-safety/70854/68).
Adoption of `LateAttrParsingExperimentalOnly` for the `counted_by`
attributed will be handled separately in another patch (likely
https://github.com/llvm/llvm-project/pull/87596).
---
clang/include/clang/Basic/Attr.td | 46 +++---
clang/include/clang/Basic/LangOptions.def | 1 +
clang/include/clang/Driver/Options.td | 7 +
clang/include/clang/Parse/Parser.h | 4 +
clang/lib/Driver/ToolChains/Clang.cpp | 3 +
clang/lib/Parse/ParseDecl.cpp | 19 ++-
.../experimental-late-parse-attributes.c | 12 ++
clang/utils/TableGen/ClangAttrEmitter.cpp | 137 ++++++++++++++++--
8 files changed, 192 insertions(+), 37 deletions(-)
create mode 100644 clang/test/Driver/experimental-late-parse-attributes.c
diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td
index dc87a8c6f022dc..da76f807cd676c 100644
--- a/clang/include/clang/Basic/Attr.td
+++ b/clang/include/clang/Basic/Attr.td
@@ -592,6 +592,16 @@ class AttrSubjectMatcherAggregateRule<AttrSubject subject> {
def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule<Named>;
+// Late Attribute parsing mode enum
+class LateAttrParseKind <int val> {
+ int Kind = val;
+}
+def LateAttrParsingNever : LateAttrParseKind<0>; // Never late parsed
+def LateAttrParsingAlways: LateAttrParseKind<1>; // Always late parsed
+// Late parsed if `-fexperimental-late-parse-attributes` is on and parsed
+// normally if off.
+def LateAttrParsingExperimentalOnly : LateAttrParseKind<2>;
+
class Attr {
// The various ways in which an attribute can be spelled in source
list<Spelling> Spellings;
@@ -603,8 +613,8 @@ class Attr {
list<Accessor> Accessors = [];
// Specify targets for spellings.
list<TargetSpecificSpelling> TargetSpecificSpellings = [];
- // Set to true for attributes with arguments which require delayed parsing.
- bit LateParsed = 0;
+ // Specifies the late parsing kind.
+ LateAttrParseKind LateParsed = LateAttrParsingNever;
// Set to false to prevent an attribute from being propagated from a template
// to the instantiation.
bit Clone = 1;
@@ -3173,7 +3183,7 @@ def DiagnoseIf : InheritableAttr {
BoolArgument<"ArgDependent", 0, /*fake*/ 1>,
DeclArgument<Named, "Parent", 0, /*fake*/ 1>];
let InheritEvenIfAlreadyPresent = 1;
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let AdditionalMembers = [{
bool isError() const { return diagnosticType == DT_Error; }
bool isWarning() const { return diagnosticType == DT_Warning; }
@@ -3472,7 +3482,7 @@ def AssertCapability : InheritableAttr {
let Spellings = [Clang<"assert_capability", 0>,
Clang<"assert_shared_capability", 0>];
let Subjects = SubjectList<[Function]>;
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3488,7 +3498,7 @@ def AcquireCapability : InheritableAttr {
GNU<"exclusive_lock_function">,
GNU<"shared_lock_function">];
let Subjects = SubjectList<[Function]>;
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3504,7 +3514,7 @@ def TryAcquireCapability : InheritableAttr {
Clang<"try_acquire_shared_capability", 0>];
let Subjects = SubjectList<[Function],
ErrorDiag>;
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3520,7 +3530,7 @@ def ReleaseCapability : InheritableAttr {
Clang<"release_generic_capability", 0>,
Clang<"unlock_function", 0>];
let Subjects = SubjectList<[Function]>;
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3539,7 +3549,7 @@ def RequiresCapability : InheritableAttr {
Clang<"requires_shared_capability", 0>,
Clang<"shared_locks_required", 0>];
let Args = [VariadicExprArgument<"Args">];
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3559,7 +3569,7 @@ def NoThreadSafetyAnalysis : InheritableAttr {
def GuardedBy : InheritableAttr {
let Spellings = [GNU<"guarded_by">];
let Args = [ExprArgument<"Arg">];
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3570,7 +3580,7 @@ def GuardedBy : InheritableAttr {
def PtGuardedBy : InheritableAttr {
let Spellings = [GNU<"pt_guarded_by">];
let Args = [ExprArgument<"Arg">];
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3581,7 +3591,7 @@ def PtGuardedBy : InheritableAttr {
def AcquiredAfter : InheritableAttr {
let Spellings = [GNU<"acquired_after">];
let Args = [VariadicExprArgument<"Args">];
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3592,7 +3602,7 @@ def AcquiredAfter : InheritableAttr {
def AcquiredBefore : InheritableAttr {
let Spellings = [GNU<"acquired_before">];
let Args = [VariadicExprArgument<"Args">];
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3603,7 +3613,7 @@ def AcquiredBefore : InheritableAttr {
def AssertExclusiveLock : InheritableAttr {
let Spellings = [GNU<"assert_exclusive_lock">];
let Args = [VariadicExprArgument<"Args">];
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3614,7 +3624,7 @@ def AssertExclusiveLock : InheritableAttr {
def AssertSharedLock : InheritableAttr {
let Spellings = [GNU<"assert_shared_lock">];
let Args = [VariadicExprArgument<"Args">];
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3627,7 +3637,7 @@ def AssertSharedLock : InheritableAttr {
def ExclusiveTrylockFunction : InheritableAttr {
let Spellings = [GNU<"exclusive_trylock_function">];
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3640,7 +3650,7 @@ def ExclusiveTrylockFunction : InheritableAttr {
def SharedTrylockFunction : InheritableAttr {
let Spellings = [GNU<"shared_trylock_function">];
let Args = [ExprArgument<"SuccessValue">, VariadicExprArgument<"Args">];
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
@@ -3651,7 +3661,7 @@ def SharedTrylockFunction : InheritableAttr {
def LockReturned : InheritableAttr {
let Spellings = [GNU<"lock_returned">];
let Args = [ExprArgument<"Arg">];
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let Subjects = SubjectList<[Function]>;
@@ -3661,7 +3671,7 @@ def LockReturned : InheritableAttr {
def LocksExcluded : InheritableAttr {
let Spellings = [GNU<"locks_excluded">];
let Args = [VariadicExprArgument<"Args">];
- let LateParsed = 1;
+ let LateParsed = LateAttrParsingAlways;
let TemplateDependent = 1;
let ParseArgumentsAsUnevaluated = 1;
let InheritEvenIfAlreadyPresent = 1;
diff --git a/clang/include/clang/Basic/LangOptions.def b/clang/include/clang/Basic/LangOptions.def
index 8ef6700ecdc78e..ed483fe8df131a 100644
--- a/clang/include/clang/Basic/LangOptions.def
+++ b/clang/include/clang/Basic/LangOptions.def
@@ -164,6 +164,7 @@ LANGOPT(ExperimentalLibrary, 1, 0, "enable unstable and experimental library fea
LANGOPT(PointerAuthIntrinsics, 1, 0, "pointer authentication intrinsics")
LANGOPT(DoubleSquareBracketAttributes, 1, 0, "'[[]]' attributes extension for all language standard modes")
+LANGOPT(ExperimentalLateParseAttributes, 1, 0, "enable experimental late parsing of attributes")
COMPATIBLE_LANGOPT(RecoveryAST, 1, 1, "Preserve expressions in AST when encountering errors")
COMPATIBLE_LANGOPT(RecoveryASTType, 1, 1, "Preserve the type in recovery expressions")
diff --git a/clang/include/clang/Driver/Options.td b/clang/include/clang/Driver/Options.td
index 9a0b5d3304ca6e..711291c0caa6bb 100644
--- a/clang/include/clang/Driver/Options.td
+++ b/clang/include/clang/Driver/Options.td
@@ -1603,6 +1603,13 @@ defm double_square_bracket_attributes : BoolFOption<"double-square-bracket-attri
LangOpts<"DoubleSquareBracketAttributes">, DefaultTrue, PosFlag<SetTrue>,
NegFlag<SetFalse>>;
+defm experimental_late_parse_attributes : BoolFOption<"experimental-late-parse-attributes",
+ LangOpts<"ExperimentalLateParseAttributes">, DefaultFalse,
+ PosFlag<SetTrue, [], [ClangOption], "Enable">,
+ NegFlag<SetFalse, [], [ClangOption], "Disable">,
+ BothFlags<[], [ClangOption, CC1Option],
+ " experimental late parsing of attributes">>;
+
defm autolink : BoolFOption<"autolink",
CodeGenOpts<"Autolink">, DefaultTrue,
NegFlag<SetFalse, [], [ClangOption, CC1Option],
diff --git a/clang/include/clang/Parse/Parser.h b/clang/include/clang/Parse/Parser.h
index c719218731c35b..d9bdb07c9e5743 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -2959,6 +2959,10 @@ class Parser : public CodeCompletionHandler {
SourceLocation AttrNameLoc,
SourceLocation *EndLoc);
+ /// isAttributeLateParsed - Return true if the attribute has arguments that
+ /// require late parsing.
+ bool isAttributeLateParsed(const IdentifierInfo &II);
+
IdentifierInfo *TryParseCXX11AttributeIdentifier(
SourceLocation &Loc,
Sema::AttributeCompletion Completion = Sema::AttributeCompletion::None,
diff --git a/clang/lib/Driver/ToolChains/Clang.cpp b/clang/lib/Driver/ToolChains/Clang.cpp
index 766a9b91e3c0ad..539861601f359f 100644
--- a/clang/lib/Driver/ToolChains/Clang.cpp
+++ b/clang/lib/Driver/ToolChains/Clang.cpp
@@ -7480,6 +7480,9 @@ void Clang::ConstructJob(Compilation &C, const JobAction &JA,
Args.addOptInFlag(CmdArgs, options::OPT_fsafe_buffer_usage_suggestions,
options::OPT_fno_safe_buffer_usage_suggestions);
+ Args.addOptInFlag(CmdArgs, options::OPT_fexperimental_late_parse_attributes,
+ options::OPT_fno_experimental_late_parse_attributes);
+
// Setup statistics file output.
SmallString<128> StatsFile = getStatsFileName(Args, Output, Input, D);
if (!StatsFile.empty()) {
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 583232f2d610d0..26e62054b92c12 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -91,11 +91,24 @@ static StringRef normalizeAttrName(StringRef Name) {
/// isAttributeLateParsed - Return true if the attribute has arguments that
/// require late parsing.
-static bool isAttributeLateParsed(const IdentifierInfo &II) {
+bool Parser::isAttributeLateParsed(const IdentifierInfo &II) {
+ // Some attributes might only be late parsed when in the experimental
+ // language mode.
+ if (getLangOpts().ExperimentalLateParseAttributes) {
+#define CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_LIST
+ bool IsExperimentalLateParseAttr =
+ llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
+#include "clang/Parse/AttrParserStringSwitches.inc"
+ .Default(false);
+#undef CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_LIST
+ if (IsExperimentalLateParseAttr)
+ return true;
+ }
+
#define CLANG_ATTR_LATE_PARSED_LIST
- return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
+ return llvm::StringSwitch<bool>(normalizeAttrName(II.getName()))
#include "clang/Parse/AttrParserStringSwitches.inc"
- .Default(false);
+ .Default(false);
#undef CLANG_ATTR_LATE_PARSED_LIST
}
diff --git a/clang/test/Driver/experimental-late-parse-attributes.c b/clang/test/Driver/experimental-late-parse-attributes.c
new file mode 100644
index 00000000000000..6b54b898afa749
--- /dev/null
+++ b/clang/test/Driver/experimental-late-parse-attributes.c
@@ -0,0 +1,12 @@
+// RUN: %clang %s -c -fexperimental-late-parse-attributes 2>&1 -### | FileCheck %s -check-prefix=CHECK-ON
+// RUN: %clang %s -c -fno-experimental-late-parse-attributes -fexperimental-late-parse-attributes 2>&1 -### | FileCheck %s -check-prefix=CHECK-ON
+
+// CHECK-ON: -cc1
+// CHECK-ON: -fexperimental-late-parse-attributes
+
+// RUN: %clang %s -c 2>&1 -### | FileCheck %s -check-prefix=CHECK-OFF
+// RUN: %clang %s -c -fno-experimental-late-parse-attributes 2>&1 -### | FileCheck %s -check-prefix=CHECK-OFF
+// RUN: %clang %s -c -fexperimental-late-parse-attributes -fno-experimental-late-parse-attributes 2>&1 -### | FileCheck %s -check-prefix=CHECK-OFF
+
+// CHECK-OFF: -cc1
+// CHECK-OFF-NOT: -fexperimental-late-parse-attributes
diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp
index 6c56f99f503df4..38a9f7226b524e 100644
--- a/clang/utils/TableGen/ClangAttrEmitter.cpp
+++ b/clang/utils/TableGen/ClangAttrEmitter.cpp
@@ -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";
}
+static void emitClangAttrLateParsedExperimentalList(RecordKeeper &Records,
+ raw_ostream &OS) {
+ OS << "#if defined(CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_LIST)\n";
+ emitClangAttrLateParsedListImpl(
+ Records, OS, LateAttrParseKind::LateAttrParsingExperimentalOnly);
+ OS << "#endif // CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_LIST\n\n";
+}
+
static bool hasGNUorCXX11Spelling(const Record &Attribute) {
std::vector<FlattenedSpelling> Spellings = GetFlattenedSpellings(Attribute);
for (const auto &I : Spellings) {
@@ -2101,9 +2179,20 @@ bool PragmaClangAttributeSupport::isAttributedSupported(
return SpecifiedResult;
// Opt-out rules:
- // An attribute requires delayed parsing (LateParsed is on)
- if (Attribute.getValueAsBit("LateParsed"))
+
+ // An attribute requires delayed parsing (LateParsed is on).
+ switch (getLateAttrParseKind(&Attribute)) {
+ case LateAttrParseKind::LateAttrParsingNever:
+ break;
+ case LateAttrParseKind::LateAttrParsingAlways:
+ return false;
+ case LateAttrParseKind::LateAttrParsingExperimentalOnly:
+ // FIXME: This is only late parsed when
+ // `-fexperimental-late-parse-attributes` is on. If that option is off
+ // then we shouldn't return here.
return false;
+ }
+
// An attribute has no GNU/CXX11 spelling
if (!hasGNUorCXX11Spelling(Attribute))
return false;
@@ -2885,8 +2974,23 @@ static void emitAttributes(RecordKeeper &Records, raw_ostream &OS,
return;
}
OS << "\n : " << SuperName << "(Ctx, CommonInfo, ";
- OS << "attr::" << R.getName() << ", "
- << (R.getValueAsBit("LateParsed") ? "true" : "false");
+ OS << "attr::" << R.getName() << ", ";
+
+ // Handle different late parsing modes.
+ switch (getLateAttrParseKind(&R)) {
+ case LateAttrParseKind::LateAttrParsingNever:
+ OS << '0';
+ break;
+ case LateAttrParseKind::LateAttrParsingAlways:
+ OS << '1';
+ break;
+ case LateAttrParseKind::LateAttrParsingExperimentalOnly:
+ // Emit code that determines if Late Parsing is enabled based on
+ // the LangOpts.
+ OS << "Ctx.getLangOpts().ExperimentalLateParseAttributes";
+ break;
+ }
+
if (Inheritable) {
OS << ", "
<< (R.getValueAsBit("InheritEvenIfAlreadyPresent") ? "true"
@@ -4843,6 +4947,7 @@ void EmitClangAttrParserStringSwitches(RecordKeeper &Records, raw_ostream &OS) {
emitClangAttrAcceptsExprPack(Records, OS);
emitClangAttrTypeArgList(Records, OS);
emitClangAttrLateParsedList(Records, OS);
+ emitClangAttrLateParsedExperimentalList(Records, OS);
}
void EmitClangAttrSubjectMatchRulesParserStringSwitches(RecordKeeper &Records,
More information about the cfe-commits
mailing list