[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/delcypher edited https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/delcypher updated https://github.com/llvm/llvm-project/pull/88596 >From 24ea6b9306e0da81b956718590bff3c3cfb9124c Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Fri, 12 Apr 2024 17:36:19 -0700 Subject: [PATCH] [Attributes] Support Attributes being declared as supporting an "extended" late parsing mode 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). * `LateAttrParseStandard` - Corresponds with the true value of `LateParsed` prior to this patch. * `LateAttrParseExperimentalExt` - A new mode described below. `LateAttrParseExperimentalExt` is an experimental extension to `LateAttrParseStandard`. Essentially this allows `Parser::ParseGNUAttributes(...)` to distinguish between these cases: 1. Only `LateAttrParseExperimentalExt` attributes should be late parsed. 2. Both `LateAttrParseExperimentalExt` and `LateAttrParseStandard` attributes should be late parsed. Callers (and indirect callers) of `Parser::ParseGNUAttributes(...)` indicate the desired behavior by setting a flag in the `LateParsedAttrList` object that is passed to the function. In addition to the above, a new driver and frontend flag (`-fexperimental-late-parse-attributes`) with a corresponding LangOpt (`ExperimentalLateParseAttributes`) is added that changes how `LateAttrParseExperimentalExt` attributes are parsed. * When the flag is disabled (default), in cases where only `LateAttrParsingExperimentalOnly` late parsing is requested, the attribute will be parsed immediately (i.e. **NOT** late parsed). This allows the attribute to act just like a `LateAttrParseStandard` attribute when the flag is disabled. * When the flag is enabled, in cases where only `LateAttrParsingExperimentalOnly` late parsing is requested, the attribute will be late parsed. The motivation behind this change is to allow the new `counted_by` attribute (part of `-fbounds-safety`) to support late parsing but **only** when `-fexperimental-late-parse-attributes` is enabled. This attribute needs to support late parsing to allow it to refer to fields later in a struct definition (or function parameters declared later). However, there isn't a precedent for supporting late attribute parsing in C so this flag allows the new behavior to exist in Clang but not be on by default. This behavior was requested as part of the `-fbounds-safety` RFC process (https://discourse.llvm.org/t/rfc-enforcing-bounds-safety-in-c-fbounds-safety/70854/68). This patch doesn't introduce any uses of `LateAttrParseExperimentalExt`. This will be added for the `counted_by` attribute in a future patch (https://github.com/llvm/llvm-project/pull/87596). A consequence is the new behavior added in this patch is not yet testable. Hence, the lack of tests covering the new behavior. rdar://125400257 --- clang/include/clang/Basic/Attr.td | 78 +++--- clang/include/clang/Basic/LangOptions.def | 1 + clang/include/clang/Driver/Options.td | 7 + clang/include/clang/Parse/Parser.h| 15 +- clang/lib/Driver/ToolChains/Clang.cpp | 3 + clang/lib/Parse/ParseDecl.cpp | 43 +- .../experimental-late-parse-attributes.c | 12 ++ clang/utils/TableGen/ClangAttrEmitter.cpp | 136 +++--- 8 files changed, 252 insertions(+), 43 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..0df80118286c89 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -592,6 +592,48 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + int Kind = val; +} + +// Never late parsed +def LateAttrParseNever : LateAttrParseKind<0>; + +// Standard late attribute parsing +// +// This is language dependent. For example: +// +// * For C++ enables late parsing of a declaration attributes +// * For C does not enable late parsing of attributes +// +def LateAttrParseStandard: LateAttrParseKind<1>; + +// Experimental extension to standard late attribute parsing +// +// This extension behaves like `LateAttrParseStandard` but allows +// late parsing attributes in more contexts. +// +// In contexts where `LateAttrParseStandard` attributes are late +// parsed, `LateAttrParseExperimentalExt` attributes will also +// be late parsed. +// +// In contexts that only late parse `LateAttrParseExperimentalExt` attributes +// (see `LateParsedAttrList::lateAttrParseExperimentalExtOnly()`) +// +// * If `-fexperimental-late-parse-attributes` +// (`LangOpts.ExperimentalLateParseAttributes`) is enabled the
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/Sirraide commented: > @Sirraide I've tried to address your feedback. Changes look fine to me. :+1: https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -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 ) { +bool Parser::isAttributeLateParsed(const IdentifierInfo ) { delcypher wrote: @rapidsna Good catch. Thinking about this some more I think the semantics you proposed creates a problem here. The semantics require (in psuedo code) that the function do this: ``` bool Parser::isAttributeLateParsed(const IdentifierInfo ) { if () { if (getLangOpts().ExperimentalLateParseAttributes) return true; } else { // Fall back to Standard late parsed behavior which means we need to return true here. return true; } return ; } ``` Which simplifies to ``` bool Parser::isAttributeLateParsed(const IdentifierInfo ) { return || ``` So basically * `getLangOpts().ExperimentalLateParseAttributes` basically does nothing. * I'm not convinced this function is the right place for us to control late parsing. Even before this patch this function would return true (regardless of input language) for attributes that were marked as `LateParsed`. E.g. for `guarded_by` this would return true I think. So I think we either need to * Use the semantics I had before but use better names (my preference) * Use the semantics you proposed but figure out where we need to conditionalize on `getLangOpts().ExperimentalLateParseAttributes`. Let me know what you think. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -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 ) { +bool Parser::isAttributeLateParsed(const IdentifierInfo ) { rapidsna wrote: I think the function also needs some update to make it so that attributes marked as `LateParseAttrExperimentalExt` will fall back to the behavior equivalent to `LateParseAttrStandard`. Currently, it seems that the function will always return `false` for attributes with `LateParseAttrExperimentalExt` when the experimental flag is disabled. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -592,6 +592,46 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + int Kind = val; +} + +// Never late parsed +def LateAttrParseNever : LateAttrParseKind<0>; + +// Standard late attribute parsing +// +// This is language dependent. For example: +// +// * For C++ enables late parsing of a declaration attributes +// * For C does not enable late parsing of attributes +// +def LateAttrParseStandard: LateAttrParseKind<1>; + +// Experimental extension to standard late attribute parsing +// +// This extension behaves like `LateAttrParseStandard` but allows +// late parsing attributes in more contexts. +// +// This extension changes behavior depending on whether the +// `-fexperimental-late-parse-attributes` +// (`LangOpts.ExperimentalLateParseAttributes`) flag is enabled. +// +// * If the flag is disabled then the attribute is parsed just like +// `LateAttrParseStandard`. +// +// * If the flag is enabled and if the attribute is being used in a context +// supported by this extension it will be late parsed. Otherwise the attribute +// will be parsed just like `LateAttrParseStandard`. +// +// Currently this extension extends `LateAttrParseStandard` by allowing: +// +// * For C, late parsing of the `counted_by` as a type or decl attribute. +// (TODO: Not implemented yet). rapidsna wrote: I don't have a strong opinion here. Having TODO in the comment seems okay to me. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -592,6 +592,46 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum rapidsna wrote: @delcypher Thanks! LGTM. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -592,6 +592,46 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + int Kind = val; +} + +// Never late parsed +def LateAttrParseNever : LateAttrParseKind<0>; + +// Standard late attribute parsing +// +// This is language dependent. For example: +// +// * For C++ enables late parsing of a declaration attributes +// * For C does not enable late parsing of attributes +// +def LateAttrParseStandard: LateAttrParseKind<1>; + +// Experimental extension to standard late attribute parsing +// +// This extension behaves like `LateAttrParseStandard` but allows +// late parsing attributes in more contexts. +// +// This extension changes behavior depending on whether the +// `-fexperimental-late-parse-attributes` +// (`LangOpts.ExperimentalLateParseAttributes`) flag is enabled. +// +// * If the flag is disabled then the attribute is parsed just like +// `LateAttrParseStandard`. +// +// * If the flag is enabled and if the attribute is being used in a context +// supported by this extension it will be late parsed. Otherwise the attribute +// will be parsed just like `LateAttrParseStandard`. +// +// Currently this extension extends `LateAttrParseStandard` by allowing: +// +// * For C, late parsing of the `counted_by` as a type or decl attribute. +// (TODO: Not implemented yet). delcypher wrote: @rapidsna Maybe I should drop this bit because of the `TODO`? https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -592,6 +592,46 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum delcypher wrote: @rapidsna I renamed the `LateAttrParseKind` definitions and updated the comments explaining the semantics. Does this look right to you? https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/delcypher updated https://github.com/llvm/llvm-project/pull/88596 >From db0483ab298cbfee2a76844e4b0f63c3ae0ff68a Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Fri, 12 Apr 2024 17:36:19 -0700 Subject: [PATCH 1/3] [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 | 133 +++--- 8 files changed, 188 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..597a8fb11e51b8 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -592,6 +592,16 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + int Kind = val; +} +def LateAttrParseNever : LateAttrParseKind<0>; // Never late parsed +def LateAttrParseAlways: LateAttrParseKind<1>; // Always late parsed +// Late parsed if `-fexperimental-late-parse-attributes` is on and parsed +// normally if off. +def LateAttrParseExperimentalOnly : LateAttrParseKind<2>; + class Attr { // The various ways in which an attribute can be spelled in source list Spellings; @@ -603,8 +613,8 @@ class Attr { list Accessors = []; // Specify targets for spellings. list TargetSpecificSpellings = []; - // Set to true for attributes with arguments which require delayed parsing. - bit LateParsed = 0; + // Specifies the late parsing kind. + LateAttrParseKind LateParsed = LateAttrParseNever; // 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]; let InheritEvenIfAlreadyPresent = 1; - let LateParsed = 1; + let LateParsed = LateAttrParseAlways; 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 = LateAttrParseAlways; 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
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,101 @@ void WriteSemanticSpellingSwitch(const std::string , OS << " }\n"; } +enum class LateAttrParseKind { Never = 0, Always = 1, ExperimentalOnly = 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. + + static constexpr StringRef LateParsedStr = "LateParsed"; + static constexpr StringRef LateAttrParseKindStr = "LateAttrParseKind"; + static constexpr StringRef KindFieldStr = "Kind"; + + auto *LAPK = Attr->getValueAsDef(LateParsedStr); + + // Typecheck the `LateParsed` field. + SmallVector SuperClasses; + LAPK->getDirectSuperClasses(SuperClasses); + if (SuperClasses.size() != 1) +PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + + "`should only have one super class"); + + 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`. + unsigned Kind = LAPK->getValueAsInt(KindFieldStr); + switch (LateAttrParseKind(Kind)) { +#define CASE(X) \ + case LateAttrParseKind::X: \ +if (LAPK->getName().compare("LateAttrParse" #X) != 0) { \ + PrintFatalError(Attr, \ + "Field `" + llvm::Twine(LateParsedStr) + "` set to `" + \ + LAPK->getName() + \ + "` but this converts to `LateAttrParseKind::" + \ + llvm::Twine(#X) + "`"); \ +} \ +return LateAttrParseKind::X; + +CASE(Never) +CASE(Always) +CASE(ExperimentalOnly) +#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 , raw_ostream ) { - OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); +static void emitClangAttrLateParsedListImpl(RecordKeeper , +raw_ostream , +LateAttrParseKind LateParseMode) { + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); for (const auto *Attr : Attrs) { -bool LateParsed = Attr->getValueAsBit("LateParsed"); +auto LateParsed = getLateAttrParseKind(Attr); delcypher wrote: Nevermind. I realized what you meant. I've resolved it. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/delcypher updated https://github.com/llvm/llvm-project/pull/88596 >From db0483ab298cbfee2a76844e4b0f63c3ae0ff68a Mon Sep 17 00:00:00 2001 From: Dan Liew Date: Fri, 12 Apr 2024 17:36:19 -0700 Subject: [PATCH 1/2] [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 | 133 +++--- 8 files changed, 188 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..597a8fb11e51b8 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -592,6 +592,16 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + int Kind = val; +} +def LateAttrParseNever : LateAttrParseKind<0>; // Never late parsed +def LateAttrParseAlways: LateAttrParseKind<1>; // Always late parsed +// Late parsed if `-fexperimental-late-parse-attributes` is on and parsed +// normally if off. +def LateAttrParseExperimentalOnly : LateAttrParseKind<2>; + class Attr { // The various ways in which an attribute can be spelled in source list Spellings; @@ -603,8 +613,8 @@ class Attr { list Accessors = []; // Specify targets for spellings. list TargetSpecificSpellings = []; - // Set to true for attributes with arguments which require delayed parsing. - bit LateParsed = 0; + // Specifies the late parsing kind. + LateAttrParseKind LateParsed = LateAttrParseNever; // 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]; let InheritEvenIfAlreadyPresent = 1; - let LateParsed = 1; + let LateParsed = LateAttrParseAlways; 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 = LateAttrParseAlways; 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
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,101 @@ void WriteSemanticSpellingSwitch(const std::string , OS << " }\n"; } +enum class LateAttrParseKind { Never = 0, Always = 1, ExperimentalOnly = 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. + + static constexpr StringRef LateParsedStr = "LateParsed"; + static constexpr StringRef LateAttrParseKindStr = "LateAttrParseKind"; + static constexpr StringRef KindFieldStr = "Kind"; + + auto *LAPK = Attr->getValueAsDef(LateParsedStr); + + // Typecheck the `LateParsed` field. + SmallVector SuperClasses; + LAPK->getDirectSuperClasses(SuperClasses); + if (SuperClasses.size() != 1) +PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + + "`should only have one super class"); + + 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`. + unsigned Kind = LAPK->getValueAsInt(KindFieldStr); + switch (LateAttrParseKind(Kind)) { +#define CASE(X) \ + case LateAttrParseKind::X: \ +if (LAPK->getName().compare("LateAttrParse" #X) != 0) { \ + PrintFatalError(Attr, \ + "Field `" + llvm::Twine(LateParsedStr) + "` set to `" + \ + LAPK->getName() + \ + "` but this converts to `LateAttrParseKind::" + \ + llvm::Twine(#X) + "`"); \ +} \ +return LateAttrParseKind::X; + +CASE(Never) +CASE(Always) +CASE(ExperimentalOnly) +#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 , raw_ostream ) { - OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); +static void emitClangAttrLateParsedListImpl(RecordKeeper , +raw_ostream , +LateAttrParseKind LateParseMode) { + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); for (const auto *Attr : Attrs) { -bool LateParsed = Attr->getValueAsBit("LateParsed"); +auto LateParsed = getLateAttrParseKind(Attr); delcypher wrote: Do you mean something like... ``` for (const auto *Attr : Attrs) { if (LateAttrParseKind LateParsed = getLateAttrParseKind(Attr); LateParsed == LateParseMode) { // All these lines have to be indented now. } } ``` ? If so I'm not really a fan of this. This forces a bunch of lines to be indented which weren't before. I much prefer to avoid that when possible to avoid the "pyramid-of-doom". Or did you mean something else? Absolutely with you on the use of `auto` here. I'll fix that. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -592,6 +592,16 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + int Kind = val; +} +def LateAttrParseNever : LateAttrParseKind<0>; // Never late parsed +def LateAttrParseAlways: LateAttrParseKind<1>; // Always late parsed +// Late parsed if `-fexperimental-late-parse-attributes` is on and parsed +// normally if off. +def LateAttrParseExperimentalOnly : LateAttrParseKind<2>; rapidsna wrote: I'd propose slightly different semantics for `LateAttrParseAlways` and `LateAttrParseExperimentalOnly`, and renaming accordingly. Before this patch, if an attribute was marked `LateParsed=1`, it meant late parsing is enabled for C++ and at the declaration attributes position. However, the same attribute was not late parsed when it is compiled for C. Therefore, having `LateParsed=1` mean "always late parsed" would be misleading. Instead, it should be something like `LateAttrParseStandard` to indicate the attribute will be late parsed in a conventional way, for C++ on the declaration attribute positions. Then, `LateParsed=2` should capture the experimental (extended) semantics to enable late parsing for C on both the decl and type attribute positions (in the future), which would be controlled by `-fexperimental-late-parse-attributes`. When the flag is disabled, it should fall back to the same behavior as `LateParsed=1`. For `counted_by` which is a C only attribute, it means no late parsing would enabled because it will be compiled only for C. Consider `guarded_by`, which is marked `LateParsed=1` and is also available for C++. Let's say we adopt `LateAttrParseExperimental` for `guarded_by`. With the flag, the code below will compile for C (though that is a lie because a naked field reference doesn't work for C atm https://github.com/llvm/llvm-project/issues/20777, but that's a separate issue and let's assume we've somehow resolved that issue). ``` struct guarded_int { int value __attribute__((guarded_by(m)); struct mutex m; }; ``` Without the flag, it won't be late parsed for C, but it should continue to be late parsed for C++ on the decl attribute positions like before. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,101 @@ void WriteSemanticSpellingSwitch(const std::string , OS << " }\n"; } +enum class LateAttrParseKind { Never = 0, Always = 1, ExperimentalOnly = 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. + + static constexpr StringRef LateParsedStr = "LateParsed"; + static constexpr StringRef LateAttrParseKindStr = "LateAttrParseKind"; + static constexpr StringRef KindFieldStr = "Kind"; + + auto *LAPK = Attr->getValueAsDef(LateParsedStr); + + // Typecheck the `LateParsed` field. + SmallVector SuperClasses; + LAPK->getDirectSuperClasses(SuperClasses); + if (SuperClasses.size() != 1) +PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + + "`should only have one super class"); + + 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`. + unsigned Kind = LAPK->getValueAsInt(KindFieldStr); + switch (LateAttrParseKind(Kind)) { +#define CASE(X) \ + case LateAttrParseKind::X: \ +if (LAPK->getName().compare("LateAttrParse" #X) != 0) { \ + PrintFatalError(Attr, \ + "Field `" + llvm::Twine(LateParsedStr) + "` set to `" + \ + LAPK->getName() + \ + "` but this converts to `LateAttrParseKind::" + \ + llvm::Twine(#X) + "`"); \ +} \ +return LateAttrParseKind::X; + +CASE(Never) +CASE(Always) +CASE(ExperimentalOnly) +#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 , raw_ostream ) { - OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); +static void emitClangAttrLateParsedListImpl(RecordKeeper , +raw_ostream , +LateAttrParseKind LateParseMode) { + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); for (const auto *Attr : Attrs) { -bool LateParsed = Attr->getValueAsBit("LateParsed"); +auto LateParsed = getLateAttrParseKind(Attr); bwendling wrote: Probably should combine this in the if statement. Also, please don't use `auto` if the type isn't obvious. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/delcypher updated https://github.com/llvm/llvm-project/pull/88596 >From db0483ab298cbfee2a76844e4b0f63c3ae0ff68a Mon Sep 17 00:00:00 2001 From: Dan Liew 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 | 133 +++--- 8 files changed, 188 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..597a8fb11e51b8 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -592,6 +592,16 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + int Kind = val; +} +def LateAttrParseNever : LateAttrParseKind<0>; // Never late parsed +def LateAttrParseAlways: LateAttrParseKind<1>; // Always late parsed +// Late parsed if `-fexperimental-late-parse-attributes` is on and parsed +// normally if off. +def LateAttrParseExperimentalOnly : LateAttrParseKind<2>; + class Attr { // The various ways in which an attribute can be spelled in source list Spellings; @@ -603,8 +613,8 @@ class Attr { list Accessors = []; // Specify targets for spellings. list TargetSpecificSpellings = []; - // Set to true for attributes with arguments which require delayed parsing. - bit LateParsed = 0; + // Specifies the late parsing kind. + LateAttrParseKind LateParsed = LateAttrParseNever; // 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]; let InheritEvenIfAlreadyPresent = 1; - let LateParsed = 1; + let LateParsed = LateAttrParseAlways; 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 = LateAttrParseAlways; 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
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/delcypher edited https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
delcypher wrote: @Sirraide I've tried to address your feedback. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/delcypher updated https://github.com/llvm/llvm-project/pull/88596 >From 31e3269126569e43cae3e4b7aba159f9a32d3c70 Mon Sep 17 00:00:00 2001 From: Dan Liew 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 | 138 -- 8 files changed, 193 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..597a8fb11e51b8 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -592,6 +592,16 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + int Kind = val; +} +def LateAttrParseNever : LateAttrParseKind<0>; // Never late parsed +def LateAttrParseAlways: LateAttrParseKind<1>; // Always late parsed +// Late parsed if `-fexperimental-late-parse-attributes` is on and parsed +// normally if off. +def LateAttrParseExperimentalOnly : LateAttrParseKind<2>; + class Attr { // The various ways in which an attribute can be spelled in source list Spellings; @@ -603,8 +613,8 @@ class Attr { list Accessors = []; // Specify targets for spellings. list TargetSpecificSpellings = []; - // Set to true for attributes with arguments which require delayed parsing. - bit LateParsed = 0; + // Specifies the late parsing kind. + LateAttrParseKind LateParsed = LateAttrParseNever; // 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]; let InheritEvenIfAlreadyPresent = 1; - let LateParsed = 1; + let LateParsed = LateAttrParseAlways; 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 = LateAttrParseAlways; 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
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
github-actions[bot] wrote: :warning: C/C++ code formatter, clang-format found issues in your code. :warning: You can test this locally with the following command: ``bash git-clang-format --diff 9bd10853e505b61f5fe2e3b3592c76787a06aa31 3554ada2c327aa6fb5ce90e26876414123bdca2d -- clang/test/Driver/experimental-late-parse-attributes.c clang/include/clang/Parse/Parser.h clang/lib/Driver/ToolChains/Clang.cpp clang/lib/Parse/ParseDecl.cpp clang/utils/TableGen/ClangAttrEmitter.cpp `` View the diff from clang-format here. ``diff diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index e06be57d6b..8aa02313da 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -1822,11 +1822,7 @@ void WriteSemanticSpellingSwitch(const std::string , OS << " }\n"; } -enum class LateAttrParseKind { - Never = 0, - Always = 1, - ExperimentalOnly = 2 -}; +enum class LateAttrParseKind { Never = 0, Always = 1, ExperimentalOnly = 2 }; static LateAttrParseKind getLateAttrParseKind(const Record *Attr) { // This function basically does @@ -1909,16 +1905,15 @@ static void emitClangAttrLateParsedListImpl(RecordKeeper , static void emitClangAttrLateParsedList(RecordKeeper , raw_ostream ) { OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; - emitClangAttrLateParsedListImpl(Records, OS, - LateAttrParseKind::Always); + emitClangAttrLateParsedListImpl(Records, OS, LateAttrParseKind::Always); OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n"; } static void emitClangAttrLateParsedExperimentalList(RecordKeeper , raw_ostream ) { OS << "#if defined(CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_LIST)\n"; - emitClangAttrLateParsedListImpl( - Records, OS, LateAttrParseKind::ExperimentalOnly); + emitClangAttrLateParsedListImpl(Records, OS, + LateAttrParseKind::ExperimentalOnly); OS << "#endif // CLANG_ATTR_LATE_PARSED_EXPERIMENTAL_LIST\n\n"; } `` https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/delcypher updated https://github.com/llvm/llvm-project/pull/88596 >From 3554ada2c327aa6fb5ce90e26876414123bdca2d Mon Sep 17 00:00:00 2001 From: Dan Liew 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 | 138 -- 8 files changed, 193 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..597a8fb11e51b8 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -592,6 +592,16 @@ class AttrSubjectMatcherAggregateRule { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + int Kind = val; +} +def LateAttrParseNever : LateAttrParseKind<0>; // Never late parsed +def LateAttrParseAlways: LateAttrParseKind<1>; // Always late parsed +// Late parsed if `-fexperimental-late-parse-attributes` is on and parsed +// normally if off. +def LateAttrParseExperimentalOnly : LateAttrParseKind<2>; + class Attr { // The various ways in which an attribute can be spelled in source list Spellings; @@ -603,8 +613,8 @@ class Attr { list Accessors = []; // Specify targets for spellings. list TargetSpecificSpellings = []; - // Set to true for attributes with arguments which require delayed parsing. - bit LateParsed = 0; + // Specifies the late parsing kind. + LateAttrParseKind LateParsed = LateAttrParseNever; // 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]; let InheritEvenIfAlreadyPresent = 1; - let LateParsed = 1; + let LateParsed = LateAttrParseAlways; 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 = LateAttrParseAlways; 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
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -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 ) { +bool Parser::isAttributeLateParsed(const IdentifierInfo ) { + // Some attributes might only be late parsed when in the experimental erichkeane wrote: AH! Urgh, i see now. Github's layout confused me. Disregard! https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -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 ) { +bool Parser::isAttributeLateParsed(const IdentifierInfo ) { + // Some attributes might only be late parsed when in the experimental delcypher wrote: @erichkeane I'm a little confused. Isn't it used here: ``` // Handle "parameterized" attributes if (!LateAttrs || !isAttributeLateParsed(*AttrName)) { ParseGNUAttributeArgs(AttrName, AttrNameLoc, Attrs, , nullptr, SourceLocation(), ParsedAttr::Form::GNU(), D); continue; } ``` in ``` void Parser::ParseGNUAttributes(ParsedAttributes , LateParsedAttrList *LateAttrs, Declarator *D) { ``` ? https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -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 ) { +bool Parser::isAttributeLateParsed(const IdentifierInfo ) { + // Some attributes might only be late parsed when in the experimental erichkeane wrote: So this function isn't actually USED anywhere. Please 'wire' it in wherever it goes. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
Sirraide wrote: > Given that a subsequent patch will add the necessary test coverage and the > above problems I think it is reasonable for explicit tests for > `LateAttrParsingExperimentalOnly` to be omitted Yeah, if it’s not used anywhere or if both prs are merged at the same time, then that seems fine; as I said, I’m not too familiar w/ the overall context around this unfortunately. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , 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 SuperClasses; + LAPK->getDirectSuperClasses(SuperClasses); + if (SuperClasses.size() != 1) { +PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + + "`should only have one super class"); + } + const char *LateAttrParseKindStr = "LateAttrParseKind"; delcypher wrote: I'll give this a try. Guess I'll find out if `llvm::Twine` is happy working with `constexpr`. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
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 Date: Fri, 12 Apr 2024 17:36:19 -0700 Subject: [PATCH 1/2] [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 { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + 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 Spellings; @@ -603,8 +613,8 @@ class Attr { list Accessors = []; // Specify targets for spellings. list 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]; 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;
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
delcypher wrote: @Sirraide Thanks for the feedback. > This should also add some tests that actually use experimentally late-parsed > attributes w/ the flag explicilty enabled/disabled. The intention is for the functionality being added to be used in a subsequent PR. This is currently sketched in this work-in-progress PR (#87596). This patch is separate from #87596 because it makes reviewing easier. I do not know how I would write tests for declaring an attribute as experimentally late parsed without that. AFAIK I'd have to use `LateAttrParsingExperimentalOnly` in `Attr.td` but * It seems undesirable to change any of the existing attributes just for the purposes of testing. * Adding a fake attribute for testing would likely impact Clang itself (i.e. the fake attribute would show up as something clang would parse) which doesn't seem desirable at all. Given that a subsequent patch will add the necessary test coverage and the above problems I think it is reasonable for explicit tests for `LateAttrParsingExperimentalOnly` to be omitted . https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -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()) { + 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; Sirraide wrote: I’d leave a comment here explaining the situation; I’m just saying that I’m not convinced there really is any ‘fixing’ this here w/o making the code around `IsSupportedByPragmaAttribute` aware of this, which seems like a strange thing to do. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , 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 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 , raw_ostream ) { - OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); +static void emitClangAttrLateParsedListImpl(RecordKeeper , +raw_ostream , +LateAttrParseKind LateParseMode) { + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); for (const auto *Attr : Attrs) { -bool LateParsed = Attr->getValueAsBit("LateParsed"); +auto LateParsed = getLateAttrParseKind(Attr); -if (LateParsed) { - std::vector Spellings = GetFlattenedSpellings(*Attr); +if (LateParsed != LateParseMode) + continue; - // FIXME: Handle non-GNU attributes - for (const auto : Spellings) { -if (I.variety() != "GNU") - continue; -OS << ".Case(\"" << I.name() << "\", " << LateParsed << ")\n"; - } +std::vector Spellings = GetFlattenedSpellings(*Attr); + +// FIXME: Handle non-GNU attributes +for (const auto : Spellings) { + if (I.variety() != "GNU") +continue; + OS << ".Case(\"" << I.name() << "\", 1)\n"; } } +} + +static void emitClangAttrLateParsedList(RecordKeeper , +raw_ostream ) { + OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; + emitClangAttrLateParsedListImpl(Records, OS, + LateAttrParseKind::LateAttrParsingAlways); OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n"; } Sirraide wrote: Oh, my bad, I somehow thought that there were two different ‘Impl’ functions. It makes sense if it’s the same function being called twice. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -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()) { + 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; delcypher wrote: So you're saying I should drop the `FIXME`? https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , 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 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 , raw_ostream ) { - OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); +static void emitClangAttrLateParsedListImpl(RecordKeeper , +raw_ostream , +LateAttrParseKind LateParseMode) { + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); for (const auto *Attr : Attrs) { -bool LateParsed = Attr->getValueAsBit("LateParsed"); +auto LateParsed = getLateAttrParseKind(Attr); -if (LateParsed) { - std::vector Spellings = GetFlattenedSpellings(*Attr); +if (LateParsed != LateParseMode) + continue; - // FIXME: Handle non-GNU attributes - for (const auto : Spellings) { -if (I.variety() != "GNU") - continue; -OS << ".Case(\"" << I.name() << "\", " << LateParsed << ")\n"; - } +std::vector Spellings = GetFlattenedSpellings(*Attr); + +// FIXME: Handle non-GNU attributes +for (const auto : Spellings) { + if (I.variety() != "GNU") +continue; + OS << ".Case(\"" << I.name() << "\", 1)\n"; } } +} + +static void emitClangAttrLateParsedList(RecordKeeper , +raw_ostream ) { + 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: Or did you mean something else? https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , 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 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 , raw_ostream ) { - OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); +static void emitClangAttrLateParsedListImpl(RecordKeeper , +raw_ostream , +LateAttrParseKind LateParseMode) { + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); for (const auto *Attr : Attrs) { -bool LateParsed = Attr->getValueAsBit("LateParsed"); +auto LateParsed = getLateAttrParseKind(Attr); -if (LateParsed) { - std::vector Spellings = GetFlattenedSpellings(*Attr); +if (LateParsed != LateParseMode) + continue; - // FIXME: Handle non-GNU attributes - for (const auto : Spellings) { -if (I.variety() != "GNU") - continue; -OS << ".Case(\"" << I.name() << "\", " << LateParsed << ")\n"; - } +std::vector Spellings = GetFlattenedSpellings(*Attr); + +// FIXME: Handle non-GNU attributes +for (const auto : Spellings) { + if (I.variety() != "GNU") +continue; + OS << ".Case(\"" << I.name() << "\", 1)\n"; } } +} + +static void emitClangAttrLateParsedList(RecordKeeper , +raw_ostream ) { + 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
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , OS << " }\n"; } +enum class LateAttrParseKind { + LateAttrParsingNever = 0, + LateAttrParsingAlways = 1, + LateAttrParsingExperimentalOnly = 2 +}; + Sirraide wrote: If it’s just for the macro here, then one option would also be to use token pasting to concatenate `LateAttrParsing` and the name of the enumerator. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , OS << " }\n"; } +enum class LateAttrParseKind { + LateAttrParsingNever = 0, + LateAttrParsingAlways = 1, + LateAttrParsingExperimentalOnly = 2 +}; + delcypher wrote: Yes. The current implementation relies on the name of the enum value and the name in `Attr.td` file being the same for the purposes of verifying the enum is in sync with the corresponding definition in the `Attr.td` file. You can see this here: ```c++ #define CASE(X)\ case LateAttrParseKind::X: \ if (LAPK->getName().compare(#X) != 0) { ``` `LAPK->getName()` is the name of the definition in the `Attr.td` file and `X` in the macro if the enum name in the `LateAttrParseKind`. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , 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 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"; Sirraide wrote: ```suggestion static constexpr StringRef KindFieldStr = "Kind"; ``` https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -2885,8 +2974,23 @@ static void emitAttributes(RecordKeeper , raw_ostream , 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()) { + case LateAttrParseKind::LateAttrParsingNever: +OS << '0'; +break; + case LateAttrParseKind::LateAttrParsingAlways: +OS << '1'; Sirraide wrote: ```suggestion OS << "true"; ``` https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , 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 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 , raw_ostream ) { - OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); +static void emitClangAttrLateParsedListImpl(RecordKeeper , +raw_ostream , +LateAttrParseKind LateParseMode) { + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); for (const auto *Attr : Attrs) { -bool LateParsed = Attr->getValueAsBit("LateParsed"); +auto LateParsed = getLateAttrParseKind(Attr); -if (LateParsed) { - std::vector Spellings = GetFlattenedSpellings(*Attr); +if (LateParsed != LateParseMode) + continue; - // FIXME: Handle non-GNU attributes - for (const auto : Spellings) { -if (I.variety() != "GNU") - continue; -OS << ".Case(\"" << I.name() << "\", " << LateParsed << ")\n"; - } +std::vector Spellings = GetFlattenedSpellings(*Attr); + +// FIXME: Handle non-GNU attributes +for (const auto : Spellings) { + if (I.variety() != "GNU") +continue; + OS << ".Case(\"" << I.name() << "\", 1)\n"; } } +} + +static void emitClangAttrLateParsedList(RecordKeeper , +raw_ostream ) { + 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 , Sirraide wrote: Same here https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -2885,8 +2974,23 @@ static void emitAttributes(RecordKeeper , raw_ostream , 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()) { + case LateAttrParseKind::LateAttrParsingNever: +OS << '0'; Sirraide wrote: ```suggestion OS << "false"; ``` https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , 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 SuperClasses; + LAPK->getDirectSuperClasses(SuperClasses); + if (SuperClasses.size() != 1) { +PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + + "`should only have one super class"); + } Sirraide wrote: ```suggestion if (SuperClasses.size() != 1) PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + "`should only have one super class"); ``` The body of the `if` is small enough that we don’t need the `{}`. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , 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 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 , raw_ostream ) { - OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); +static void emitClangAttrLateParsedListImpl(RecordKeeper , +raw_ostream , +LateAttrParseKind LateParseMode) { + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); for (const auto *Attr : Attrs) { -bool LateParsed = Attr->getValueAsBit("LateParsed"); +auto LateParsed = getLateAttrParseKind(Attr); -if (LateParsed) { - std::vector Spellings = GetFlattenedSpellings(*Attr); +if (LateParsed != LateParseMode) + continue; - // FIXME: Handle non-GNU attributes - for (const auto : Spellings) { -if (I.variety() != "GNU") - continue; -OS << ".Case(\"" << I.name() << "\", " << LateParsed << ")\n"; - } +std::vector Spellings = GetFlattenedSpellings(*Attr); + +// FIXME: Handle non-GNU attributes +for (const auto : Spellings) { + if (I.variety() != "GNU") +continue; + OS << ".Case(\"" << I.name() << "\", 1)\n"; } } +} + +static void emitClangAttrLateParsedList(RecordKeeper , +raw_ostream ) { + OS << "#if defined(CLANG_ATTR_LATE_PARSED_LIST)\n"; + emitClangAttrLateParsedListImpl(Records, OS, + LateAttrParseKind::LateAttrParsingAlways); OS << "#endif // CLANG_ATTR_LATE_PARSED_LIST\n\n"; } Sirraide wrote: Imo the code in `emit...Impl()` can just be inlined into this since it doesn’t have any early `return`s or anything like that anyway. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -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()) { + 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; Sirraide wrote: Hmm, I’d probably just keep returning `false` here as there is no good way to handle this here—at least not that I can think of. Not supporting it here if it may sometimes be late parsed is probably fine. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , 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"; Sirraide wrote: ```suggestion static constexpr StringRef LateParsedStr = "LateParsed"; ``` https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , OS << " }\n"; } +enum class LateAttrParseKind { + LateAttrParsingNever = 0, + LateAttrParsingAlways = 1, + LateAttrParsingExperimentalOnly = 2 +}; + Sirraide wrote: This seems a bit verbose seeing as it’s a scoped enum anyway. Is there a reason why these aren’t just called `Never` etc. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , 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 SuperClasses; + LAPK->getDirectSuperClasses(SuperClasses); + if (SuperClasses.size() != 1) { +PrintFatalError(Attr, "Field `" + llvm::Twine(LateParsedStr) + + "`should only have one super class"); + } + const char *LateAttrParseKindStr = "LateAttrParseKind"; Sirraide wrote: ```suggestion static constexpr StringRef LateAttrParseKindStr = "LateAttrParseKind"; ``` https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/Sirraide requested changes to this pull request. Not too familiar w/ the overall context of this, so I can only comment on the implementation. This should also add some tests that actually use experimentally late-parsed attributes w/ the flag explicilty enabled/disabled. https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
@@ -1822,28 +1822,106 @@ void WriteSemanticSpellingSwitch(const std::string , 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 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"; Sirraide wrote: I personally would also group the field name constants at the top of the function so they’re all in one place, but that might also just be a me thing; it’s not that important https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/Sirraide edited https://github.com/llvm/llvm-project/pull/88596 ___ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
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 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 { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + 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 Spellings; @@ -603,8 +613,8 @@ class Attr { list Accessors = []; // Specify targets for spellings. list 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]; 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; +
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
llvmbot wrote: @llvm/pr-subscribers-clang Author: Dan Liew (delcypher) Changes [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). --- Patch is 20.25 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/88596.diff 8 Files Affected: - (modified) clang/include/clang/Basic/Attr.td (+28-18) - (modified) clang/include/clang/Basic/LangOptions.def (+1) - (modified) clang/include/clang/Driver/Options.td (+7) - (modified) clang/include/clang/Parse/Parser.h (+4) - (modified) clang/lib/Driver/ToolChains/Clang.cpp (+3) - (modified) clang/lib/Parse/ParseDecl.cpp (+16-3) - (added) clang/test/Driver/experimental-late-parse-attributes.c (+12) - (modified) clang/utils/TableGen/ClangAttrEmitter.cpp (+121-16) ``diff 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 { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + 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 Spellings; @@ -603,8 +613,8 @@ class Attr { list Accessors = []; // Specify targets for spellings. list 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]; 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
[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)
https://github.com/delcypher created https://github.com/llvm/llvm-project/pull/88596 [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). >From 9e4809533c56431731c1f20a2eb951bc1cc5c60e Mon Sep 17 00:00:00 2001 From: Dan Liew 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 { def SubjectMatcherForNamed : AttrSubjectMatcherAggregateRule; +// Late Attribute parsing mode enum +class LateAttrParseKind { + int Kind = val; +} +def LateAttrParsingNever : LateAttrParseKind<0>; // Never late