rymiel created this revision. rymiel added reviewers: HazardyKnusperkeks, owenpan, MyDeveloperDay. Herald added a project: All. rymiel requested review of this revision. Herald added a project: clang. Herald added a subscriber: cfe-commits.
This patch properly recognizes the generic selection expression introduced in C11, by adding an additional token type for the colons present in such expressions. Previously, they would be recognized as "inline ASM colons" purely by the fact that those are the last thing checked for. I tried to avoid adding an addition token type, but since colons by default like having spaces around them, I chose to add a new type so that no space is added after the type selector. Currently, no aspect of the formatting of these expressions in able to be configured, as I'm not sure what could even be configured here. One notable thing is that association list is always formatted as either entirely on one line, if it can fit, or with line breaks after every comma in the expression (also after the controlling expr.) This visually makes them more similar to switch statements when long, matching the behaviour of the selection expression, being that of a sort of switch on types, but also allows for terseness when only selecting for a few things. Fixes https://github.com/llvm/llvm-project/issues/18080 Repository: rG LLVM Github Monorepo https://reviews.llvm.org/D139211 Files: clang/lib/Format/ContinuationIndenter.cpp clang/lib/Format/FormatToken.h clang/lib/Format/TokenAnnotator.cpp clang/unittests/Format/FormatTest.cpp clang/unittests/Format/TokenAnnotatorTest.cpp
Index: clang/unittests/Format/TokenAnnotatorTest.cpp =================================================================== --- clang/unittests/Format/TokenAnnotatorTest.cpp +++ clang/unittests/Format/TokenAnnotatorTest.cpp @@ -1105,6 +1105,14 @@ EXPECT_TOKEN(Tokens[1], tok::identifier, TT_FunctionDeclarationName); } +TEST_F(TokenAnnotatorTest, UnderstandsC11GenericSelection) { + auto Tokens = annotate("_Generic(x, int: 1, default: 0)"); + ASSERT_EQ(Tokens.size(), 13u) << Tokens; + EXPECT_TOKEN(Tokens[0], tok::kw__Generic, TT_Unknown); + EXPECT_TOKEN(Tokens[5], tok::colon, TT_GenericSelectionColon); + EXPECT_TOKEN(Tokens[9], tok::colon, TT_GenericSelectionColon); +} + TEST_F(TokenAnnotatorTest, UnderstandsVerilogOperators) { auto Annotate = [this](llvm::StringRef Code) { return annotate(Code, getLLVMStyle(FormatStyle::LK_Verilog)); Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -22909,6 +22909,18 @@ verifyFormat("x = (_Atomic( uint64_t ))&a;", Style); } +TEST_F(FormatTest, C11Generic) { + verifyFormat("_Generic(x, int: 1, default: 0)"); + verifyFormat("#define cbrt(X) _Generic((X), float: cbrtf, default: cbrt)(X)"); + verifyFormat("_Generic(x,\n" + " float: f,\n" + " default: d,\n" + " long double: ld,\n" + " float _Complex: fc,\n" + " double _Complex: dc,\n" + " long double _Complex: ldc)"); +} + TEST_F(FormatTest, AmbersandInLamda) { // Test case reported in https://bugs.llvm.org/show_bug.cgi?id=41899 FormatStyle AlignStyle = getLLVMStyle(); Index: clang/lib/Format/TokenAnnotator.cpp =================================================================== --- clang/lib/Format/TokenAnnotator.cpp +++ clang/lib/Format/TokenAnnotator.cpp @@ -321,6 +321,10 @@ } else if (isLambdaParameterList(&OpeningParen)) { // This is a parameter list of a lambda expression. Contexts.back().IsExpression = false; + } else if (OpeningParen.Previous && + OpeningParen.Previous->is(tok::kw__Generic)) { + Contexts.back().ContextType = Context::C11GenericSelection; + Contexts.back().IsExpression = true; } else if (Line.InPPDirective && (!OpeningParen.Previous || !OpeningParen.Previous->is(tok::identifier))) { @@ -1026,6 +1030,8 @@ } } else if (Contexts.back().ColonIsForRangeExpr) { Tok->setType(TT_RangeBasedForLoopColon); + } else if (Contexts.back().ContextType == Context::C11GenericSelection) { + Tok->setType(TT_GenericSelectionColon); } else if (CurrentToken && CurrentToken->is(tok::numeric_constant)) { Tok->setType(TT_BitFieldColon); } else if (Contexts.size() == 1 && @@ -1621,6 +1627,8 @@ StructArrayInitializer, // Like in `static_cast<int>`. TemplateArgument, + // C11 _Generic selection + C11GenericSelection, } ContextType = Unknown; }; @@ -4170,6 +4178,8 @@ return false; if (Right.is(TT_CSharpNamedArgumentColon)) return false; + if (Right.is(TT_GenericSelectionColon)) + return false; if (Right.is(TT_BitFieldColon)) { return Style.BitFieldColonSpacing == FormatStyle::BFCS_Both || Style.BitFieldColonSpacing == FormatStyle::BFCS_Before; Index: clang/lib/Format/FormatToken.h =================================================================== --- clang/lib/Format/FormatToken.h +++ clang/lib/Format/FormatToken.h @@ -70,6 +70,8 @@ TYPE(FunctionLBrace) \ TYPE(FunctionLikeOrFreestandingMacro) \ TYPE(FunctionTypeLParen) \ + /* The colons as part of a C11 _Generic selection */ \ + TYPE(GenericSelectionColon) \ /* The colon at the end of a goto label or a case label. Currently only used \ * for Verilog. */ \ TYPE(GotoLabelColon) \ Index: clang/lib/Format/ContinuationIndenter.cpp =================================================================== --- clang/lib/Format/ContinuationIndenter.cpp +++ clang/lib/Format/ContinuationIndenter.cpp @@ -1682,8 +1682,12 @@ (State.Line->Type != LT_ObjCDecl && Style.BinPackParameters) || (State.Line->Type == LT_ObjCDecl && ObjCBinPackProtocolList); + bool GenericSelection = + Current.getPreviousNonComment() && + Current.getPreviousNonComment()->is(tok::kw__Generic); + AvoidBinPacking = - (CurrentState.IsCSharpGenericTypeConstraint) || + (CurrentState.IsCSharpGenericTypeConstraint) || GenericSelection || (Style.isJavaScript() && EndsInComma) || (State.Line->MustBeDeclaration && !BinPackDeclaration) || (!State.Line->MustBeDeclaration && !Style.BinPackArguments) ||
_______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits