diff --git a/clang/lib/Format/ContinuationIndenter.cpp b/clang/lib/Format/ContinuationIndenter.cpp --- a/clang/lib/Format/ContinuationIndenter.cpp +++ b/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) || diff --git a/clang/lib/Format/FormatToken.h b/clang/lib/Format/FormatToken.h --- a/clang/lib/Format/FormatToken.h +++ b/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) \ diff --git a/clang/lib/Format/TokenAnnotator.cpp b/clang/lib/Format/TokenAnnotator.cpp --- a/clang/lib/Format/TokenAnnotator.cpp +++ b/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`. 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; diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp --- a/clang/unittests/Format/FormatTest.cpp +++ b/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(); diff --git a/clang/unittests/Format/TokenAnnotatorTest.cpp b/clang/unittests/Format/TokenAnnotatorTest.cpp --- a/clang/unittests/Format/TokenAnnotatorTest.cpp +++ b/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));