std::max(State.Column, NewParenState.Indent), CurrentState.LastSpace);
}
+ // Special case for generic selection expressions, its comma-separated
+ // expressions are not aligned to the opening paren like regular calls, but
+ // rather continuation-indented relative to the _Generic keyword.
+ if (Previous && Previous->endsSequence(tok::l_paren, tok::kw__Generic))
+ NewParenState.Indent = CurrentState.LastSpace;
+
if (Previous &&
(Previous->getPrecedence() == prec::Assignment ||
Previous->isOneOf(tok::kw_return, TT_RequiresClause) ||
(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) ||
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) \
Contexts.back().IsExpression = false;
} else if (OpeningParen.is(TT_RequiresExpressionLParen)) {
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))) {
}
} 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 &&
StructArrayInitializer,
// Like in `static_cast<int>`.
TemplateArgument,
+ // C11 _Generic selection.
+ C11GenericSelection,
} ContextType = Unknown;
};
return 100;
}
if (Left.is(tok::l_paren) && Left.Previous &&
- (Left.Previous->is(tok::kw_for) || Left.Previous->isIf())) {
+ (Left.Previous->isOneOf(tok::kw_for, tok::kw__Generic) ||
+ Left.Previous->isIf())) {
return 1000;
}
if (Left.is(tok::equal) && InFunctionDecl)
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;
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, const char *: 1, char *const: 16, int: 8);");
+ verifyFormat("_Generic(x, int: f1, const int: f2)();");
+ verifyFormat("_Generic(x, struct A: 1, void (*)(void): 2);");
+
+ 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)");
+
+ FormatStyle Style = getLLVMStyle();
+ Style.ColumnLimit = 40;
+ verifyFormat("#define LIMIT_MAX(T) \\\n"
+ " _Generic(((T)0), \\\n"
+ " unsigned int: UINT_MAX, \\\n"
+ " unsigned long: ULONG_MAX, \\\n"
+ " unsigned long long: ULLONG_MAX)",
+ Style);
+ verifyFormat("_Generic(x,\n"
+ " struct A: 1,\n"
+ " void (*)(void): 2);",
+ Style);
+
+ Style.ContinuationIndentWidth = 2;
+ verifyFormat("_Generic(x,\n"
+ " struct A: 1,\n"
+ " void (*)(void): 2);",
+ Style);
+}
+
TEST_F(FormatTest, AmbersandInLamda) {
// Test case reported in https://bugs.llvm.org/show_bug.cgi?id=41899
FormatStyle AlignStyle = getLLVMStyle();
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));