diff options
author | Björn Schäpers <bjoern@hazardy.de> | 2022-03-02 01:15:09 +0300 |
---|---|---|
committer | Björn Schäpers <bjoern@hazardy.de> | 2022-03-13 00:44:24 +0300 |
commit | 8b4d68bf65ef145333aae82683b5fcee29b38dc2 (patch) | |
tree | 1f3e2cb9c2fb03d702932ce63a3bf0a007f98825 /clang | |
parent | 4f320ca4ba15dcf9dda8775f74745aab7d3633a6 (diff) |
[clang-format] Handle builtins in constraint expression
Fixes https://github.com/llvm/llvm-project/issues/54106
Differential Revision: https://reviews.llvm.org/D120774
Diffstat (limited to 'clang')
-rw-r--r-- | clang/lib/Format/UnwrappedLineParser.cpp | 53 | ||||
-rw-r--r-- | clang/unittests/Format/FormatTest.cpp | 12 |
2 files changed, 40 insertions, 25 deletions
diff --git a/clang/lib/Format/UnwrappedLineParser.cpp b/clang/lib/Format/UnwrappedLineParser.cpp index 994b197347bc..3a245b8b5fa0 100644 --- a/clang/lib/Format/UnwrappedLineParser.cpp +++ b/clang/lib/Format/UnwrappedLineParser.cpp @@ -3132,30 +3132,6 @@ void UnwrappedLineParser::parseConstraintExpression() { 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: @@ -3232,7 +3208,34 @@ void UnwrappedLineParser::parseConstraintExpression() { break; default: - return; + if (!FormatTok->Tok.getIdentifierInfo()) { + // Identifiers are part of the default case, we check for more then + // tok::identifier to handle builtin type traits. + 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()); } diff --git a/clang/unittests/Format/FormatTest.cpp b/clang/unittests/Format/FormatTest.cpp index b344ac33cd58..37a42382e8f8 100644 --- a/clang/unittests/Format/FormatTest.cpp +++ b/clang/unittests/Format/FormatTest.cpp @@ -23810,6 +23810,18 @@ TEST_F(FormatTest, Concepts) { verifyFormat("template <typename T>\n" "concept Node = std::is_object_v<T>;"); + verifyFormat("template <class T>\n" + "concept integral = __is_integral(T);"); + + verifyFormat("template <class T>\n" + "concept is2D = __array_extent(T, 1) == 2;"); + + verifyFormat("template <class T>\n" + "concept isRhs = __is_rvalue_expr(std::declval<T>() + 2)"); + + verifyFormat("template <class T, class T2>\n" + "concept Same = __is_same_as<T, T2>;"); + auto Style = getLLVMStyle(); Style.BreakBeforeConceptDeclarations = FormatStyle::BBCDS_Allowed; |