https://github.com/aalmkainzi updated 
https://github.com/llvm/llvm-project/pull/210353

>From 3377a5323cca1654f8a8505ff063bc60dea697b8 Mon Sep 17 00:00:00 2001
From: Abdulmalek Almkainzi <[email protected]>
Date: Fri, 17 Jul 2026 00:33:31 +0300
Subject: [PATCH] Fixed #207357

added a new ParsingGenericAssociationType flag that is managed by 
GenericAssociationTypeRAIIObject. Using that, 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.
---
 clang/include/clang/Parse/Parser.h               | 13 +++++++++++++
 clang/include/clang/Parse/RAIIObjectsForParser.h | 15 +++++++++++++++
 clang/lib/Parse/ParseDecl.cpp                    |  4 +++-
 clang/lib/Parse/ParseDeclCXX.cpp                 |  3 ++-
 clang/lib/Parse/ParseExpr.cpp                    |  3 ++-
 clang/lib/Parse/ParseTentative.cpp               |  8 ++++++++
 clang/test/Parser/c23-enum-generic-assoc.c       | 10 ++++++++++
 7 files changed, 53 insertions(+), 3 deletions(-)
 create mode 100644 clang/test/Parser/c23-enum-generic-assoc.c

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

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

Reply via email to