Index: clang/lib/Format/UnwrappedLineParser.cpp =================================================================== --- clang/lib/Format/UnwrappedLineParser.cpp +++ clang/lib/Format/UnwrappedLineParser.cpp @@ -3085,30 +3085,6 @@ return; break; - case tok::identifier: - // We need to differentiate identifiers for a template deduction guide, - // variables, or function return types (the constraint expression has - // ended before that), and basically all other cases. But it's easier to - // check the other way around. - assert(FormatTok->Previous); - switch (FormatTok->Previous->Tok.getKind()) { - case tok::coloncolon: // Nested identifier. - case tok::ampamp: // Start of a function or variable for the - case tok::pipepipe: // constraint expression. - case tok::kw_requires: // Initial identifier of a requires clause. - case tok::equal: // Initial identifier of a concept declaration. - break; - default: - return; - } - - // Read identifier with optional template declaration. - nextToken(); - if (FormatTok->is(tok::less)) - parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, - /*ClosingBraceKind=*/tok::greater); - break; - case tok::kw_const: case tok::semi: case tok::kw_class: @@ -3184,8 +3160,33 @@ parseParens(); break; + case tok::identifier: default: - return; + if (!FormatTok->Tok.getIdentifierInfo()) + return; + + // We need to differentiate identifiers for a template deduction guide, + // variables, or function return types (the constraint expression has + // ended before that), and basically all other cases. But it's easier to + // check the other way around. + assert(FormatTok->Previous); + switch (FormatTok->Previous->Tok.getKind()) { + case tok::coloncolon: // Nested identifier. + case tok::ampamp: // Start of a function or variable for the + case tok::pipepipe: // constraint expression. + case tok::kw_requires: // Initial identifier of a requires clause. + case tok::equal: // Initial identifier of a concept declaration. + break; + default: + return; + } + + // Read identifier with optional template declaration. + nextToken(); + if (FormatTok->is(tok::less)) + parseBracedList(/*ContinueOnSemicolons=*/false, /*IsEnum=*/false, + /*ClosingBraceKind=*/tok::greater); + break; } } while (!eof()); } Index: clang/unittests/Format/FormatTest.cpp =================================================================== --- clang/unittests/Format/FormatTest.cpp +++ clang/unittests/Format/FormatTest.cpp @@ -23743,6 +23743,18 @@ verifyFormat("template \n" "concept Node = std::is_object_v;"); + verifyFormat("template \n" + "concept integral = __is_integral(T);"); + + verifyFormat("template \n" + "concept is2D = __array_extent(T, 1) == 2;"); + + verifyFormat("template \n" + "concept isRhs = __is_rvalue_expr(std::declval() + 2)"); + + verifyFormat("template \n" + "concept Same = __is_same_as;"); + auto Style = getLLVMStyle(); Style.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Allowed;