[clang] [Attributes] Support Attributes being declared as only supporting late parsing when passing an experimental feature flag (PR #88596)

2024-04-19 Thread Dan Liew via cfe-commits

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)

2024-04-19 Thread Dan Liew via cfe-commits

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)

2024-04-18 Thread via cfe-commits

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)

2024-04-18 Thread Dan Liew via cfe-commits


@@ -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)

2024-04-17 Thread Yeoul Na via cfe-commits


@@ -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)

2024-04-17 Thread Yeoul Na via cfe-commits


@@ -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)

2024-04-17 Thread Yeoul Na via cfe-commits


@@ -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)

2024-04-15 Thread Dan Liew via cfe-commits


@@ -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)

2024-04-15 Thread Dan Liew via cfe-commits


@@ -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)

2024-04-15 Thread Dan Liew via cfe-commits

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)

2024-04-15 Thread Dan Liew via cfe-commits


@@ -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)

2024-04-15 Thread Dan Liew via cfe-commits

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)

2024-04-15 Thread Dan Liew via cfe-commits


@@ -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)

2024-04-15 Thread Yeoul Na via cfe-commits


@@ -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)

2024-04-15 Thread Bill Wendling via cfe-commits


@@ -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)

2024-04-15 Thread Dan Liew via cfe-commits

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)

2024-04-15 Thread Dan Liew via cfe-commits

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)

2024-04-15 Thread Dan Liew via cfe-commits

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)

2024-04-15 Thread Dan Liew via cfe-commits

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)

2024-04-15 Thread via cfe-commits

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)

2024-04-15 Thread Dan Liew via cfe-commits

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)

2024-04-15 Thread Erich Keane via cfe-commits


@@ -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)

2024-04-15 Thread Dan Liew via cfe-commits


@@ -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)

2024-04-15 Thread Erich Keane via cfe-commits


@@ -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)

2024-04-14 Thread via cfe-commits

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)

2024-04-13 Thread Dan Liew via cfe-commits


@@ -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)

2024-04-13 Thread Dan Liew via cfe-commits

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)

2024-04-13 Thread Dan Liew via cfe-commits

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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread Dan Liew via cfe-commits


@@ -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)

2024-04-13 Thread Dan Liew via cfe-commits


@@ -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)

2024-04-13 Thread Dan Liew via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread Dan Liew via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits

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)

2024-04-13 Thread via cfe-commits


@@ -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)

2024-04-13 Thread via cfe-commits

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)

2024-04-12 Thread Dan Liew via cfe-commits

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)

2024-04-12 Thread via cfe-commits

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)

2024-04-12 Thread Dan Liew via cfe-commits

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