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
