[clang] Fixed #207357 (PR #210353)
Abdulmalek Almkainzi via cfe-commits
cfe-commits at lists.llvm.org
Fri Jul 17 13:50:25 PDT 2026
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 <aalmkainzi at gmail.com>
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
More information about the cfe-commits
mailing list