llvmorg-github-actions[bot] wrote:

<!--LLVM PR SUMMARY COMMENT-->

@llvm/pr-subscribers-clang

Author: Abdulmalek Almkainzi (aalmkainzi)

<details>
<summary>Changes</summary>

added a new `ParsingGenericAssociationType` flag that is managed by 
`GenericAssociationTypeRAIIObject`. If that flag is true, when encountering a 
`:` after enum name, try to parse next token as a type, if successful, then 
that's the underlying type, if failed, then that is the end of the enum 
declaration, and the colon will be parsed as the generic association.

to check if the next tokens are a type, I added a new function 
`isNextCXXTypeId`, which works the same as `isCXXTypeId`, but starts the check 
one token ahead.

---
Full diff: https://github.com/llvm/llvm-project/pull/210353.diff


7 Files Affected:

- (modified) clang/include/clang/Parse/Parser.h (+13) 
- (modified) clang/include/clang/Parse/RAIIObjectsForParser.h (+15) 
- (modified) clang/lib/Parse/ParseDecl.cpp (+3-1) 
- (modified) clang/lib/Parse/ParseDeclCXX.cpp (+2-1) 
- (modified) clang/lib/Parse/ParseExpr.cpp (+2-1) 
- (modified) clang/lib/Parse/ParseTentative.cpp (+8) 
- (added) clang/test/Parser/c23-enum-generic-assoc.c (+10) 


``````````diff
diff --git a/clang/include/clang/Parse/Parser.h 
b/clang/include/clang/Parse/Parser.h
index 163aa483a84e3..f6b259ddaff8d 100644
--- a/clang/include/clang/Parse/Parser.h
+++ b/clang/include/clang/Parse/Parser.h
@@ -279,6 +279,7 @@ class Parser : public CodeCompletionHandler {
 
 public:
   friend class ColonProtectionRAIIObject;
+  friend class GenericAssociationTypeRAIIObject;
   friend class PoisonSEHIdentifiersRAIIObject;
   friend class ParenBraceBracketBalancer;
   friend class BalancedDelimiterTracker;
@@ -4490,6 +4491,11 @@ class Parser : public CodeCompletionHandler {
   /// ColonProtectionRAIIObject RAII object.
   bool ColonIsSacred;
 
+  // ParsingGenericAssociationType - Currently parsing the typename in
+  // _Generic association. This is to consume the colon if what comes after it
+  // is a type.
+  bool ParsingGenericAssociationType;
+
   /// ParseCXXAmbiguousParenExpression - We have parsed the left paren of a
   /// parenthesized ambiguous type-id. This uses tentative parsing to
   /// disambiguate based on the context past the parens.
@@ -8677,6 +8683,13 @@ class Parser : public CodeCompletionHandler {
     return isCXXTypeId(Context, isAmbiguous);
   }
 
+  bool isNextCXXTypeId(TentativeCXXTypeIdContext Context, bool &isAmbiguous);
+
+  bool isNextCXXTypeId(TentativeCXXTypeIdContext Context) {
+    bool isAmbiguous;
+    return isNextCXXTypeId(Context, isAmbiguous);
+  }
+
   /// TPResult - Used as the result value for functions whose purpose is to
   /// disambiguate C++ constructs by "tentatively parsing" them.
   enum class TPResult { True, False, Ambiguous, Error };
diff --git a/clang/include/clang/Parse/RAIIObjectsForParser.h 
b/clang/include/clang/Parse/RAIIObjectsForParser.h
index 3adcbfe9d7016..747dbe90b1bf6 100644
--- a/clang/include/clang/Parse/RAIIObjectsForParser.h
+++ b/clang/include/clang/Parse/RAIIObjectsForParser.h
@@ -290,6 +290,21 @@ namespace clang {
     }
   };
 
+  class GenericAssociationTypeRAIIObject {
+    Parser &P;
+    bool OldVal;
+
+  public:
+    GenericAssociationTypeRAIIObject(Parser &p, bool Value = true)
+        : P(p), OldVal(P.ParsingGenericAssociationType) {
+      P.ParsingGenericAssociationType = Value;
+    }
+
+    void restore() { P.ParsingGenericAssociationType = OldVal; }
+
+    ~GenericAssociationTypeRAIIObject() { restore(); }
+  };
+
   /// Activates OpenMP parsing mode to preseve OpenMP specific annotation
   /// tokens.
   class ParsingOpenMPDirectiveRAII {
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 88f07bb104fcb..6f551a00df0e9 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -5200,7 +5200,9 @@ void Parser::ParseEnumSpecifier(SourceLocation StartLoc, 
DeclSpec &DS,
       getCurScope()->isClassScope() && ScopedEnumKWLoc.isInvalid() && Name;
 
   // Parse the fixed underlying type.
-  if (Tok.is(tok::colon)) {
+  if (Tok.is(tok::colon) &&
+      (!ParsingGenericAssociationType ||
+       isNextCXXTypeId(TentativeCXXTypeIdContext::Unambiguous))) {
     // This might be an enum-base or part of some unrelated enclosing context.
     //
     // 'enum E : base' is permitted in two circumstances:
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index d7a9c72eb2da8..40b08b1bab09b 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -1479,7 +1479,8 @@ bool Parser::isValidAfterTypeSpecifier(bool 
CouldBeBitfield) {
     return true;
   case tok::colon:
     return CouldBeBitfield || // enum E { ... }   :         2;
-           ColonIsSacred;     // _Generic(..., enum E :     2);
+           ColonIsSacred ||
+           ParsingGenericAssociationType; // _Generic(..., enum E :     2);
   // Microsoft compatibility
   case tok::kw___cdecl:      // struct foo {...} __cdecl      x;
   case tok::kw___fastcall:   // struct foo {...} __fastcall   x;
diff --git a/clang/lib/Parse/ParseExpr.cpp b/clang/lib/Parse/ParseExpr.cpp
index 74209f579776d..fac8a6897c071 100644
--- a/clang/lib/Parse/ParseExpr.cpp
+++ b/clang/lib/Parse/ParseExpr.cpp
@@ -3104,7 +3104,8 @@ ExprResult Parser::ParseGenericSelectionExpression() {
       DefaultLoc = ConsumeToken();
       Ty = nullptr;
     } else {
-      ColonProtectionRAIIObject X(*this);
+      GenericAssociationTypeRAIIObject X(*this);
+
       TypeResult TR = ParseTypeName(nullptr, DeclaratorContext::Association);
       if (TR.isInvalid()) {
         SkipUntil(tok::r_paren, StopAtSemi);
diff --git a/clang/lib/Parse/ParseTentative.cpp 
b/clang/lib/Parse/ParseTentative.cpp
index 1477fc38bcc6d..1969af9110816 100644
--- a/clang/lib/Parse/ParseTentative.cpp
+++ b/clang/lib/Parse/ParseTentative.cpp
@@ -602,6 +602,14 @@ bool Parser::isCXXTypeId(TentativeCXXTypeIdContext 
Context, bool &isAmbiguous) {
   return TPR == TPResult::True;
 }
 
+bool Parser::isNextCXXTypeId(TentativeCXXTypeIdContext Context,
+                             bool &isAmbiguous) {
+  RevertingTentativeParsingAction PA(*this);
+  ConsumeToken();
+  bool ret = isCXXTypeId(Context, isAmbiguous);
+  return ret;
+}
+
 CXX11AttributeKind
 Parser::isCXX11AttributeSpecifier(bool Disambiguate,
                                   bool OuterMightBeMessageSend) {
diff --git a/clang/test/Parser/c23-enum-generic-assoc.c 
b/clang/test/Parser/c23-enum-generic-assoc.c
new file mode 100644
index 0000000000000..b0ea715bacc36
--- /dev/null
+++ b/clang/test/Parser/c23-enum-generic-assoc.c
@@ -0,0 +1,10 @@
+// RUN: %clang_cc1 -fsyntax-only -verify -std=c23 %s
+// expected-no-diagnostics
+
+typedef long l;
+
+_Static_assert(_Generic(0L, enum E : long { A } : 0, int: 1) == 0, "");
+
+_Static_assert(_Generic(0L, enum E : 0, int: 1) == 0, "");
+
+_Static_assert(_Generic(0L, enum A : l { B } : 0, int: 1) == 0, "");
\ No newline at end of file

``````````

</details>


https://github.com/llvm/llvm-project/pull/210353
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to