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
