Skip to content

Commit b1eeec6

Browse files
committed
[clang-format] Remove special logic for parsing concept definitions.
Previously, clang-format relied on a special method to parse concept definitions, `UnwrappedLineParser::parseConcept()`, which deferred to `UnwrappedLineParser::parseConstraintExpression()`. This is problematic, because the C++ grammar treats concepts and requires clauses differently, causing issues such as llvm#55898 and llvm#58130. This patch removes `parseConcept`, letting the formatter parse concept definitions as more like what they actually are, fancy bool definitions. NOTE that because of this, some long concept definitions change in their formatting, as can be seen in the changed tests. This is because of a change in split penalties, caused by a change in MightBeFunctionDecl on the concept definition line, which was previously `true` but with this patch is now `false`. One might argue that `false` is a more "correct" value for concept definitions, but I'd be fine with setting it to `true` again to maintain compatibility with previous versions. Fixes llvm#58130 Depends on D140330 Reviewed By: HazardyKnusperkeks, owenpan, MyDeveloperDay Differential Revision: https://reviews.llvm.org/D140339
1 parent 54fab18 commit b1eeec6

File tree

4 files changed

+28
-51
lines changed

4 files changed

+28
-51
lines changed

clang/lib/Format/TokenAnnotator.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1690,8 +1690,8 @@ class AnnotatingParser {
16901690
if (!Tok)
16911691
return false;
16921692

1693-
if (Tok->isOneOf(tok::kw_class, tok::kw_enum, tok::kw_concept,
1694-
tok::kw_struct, tok::kw_using)) {
1693+
if (Tok->isOneOf(tok::kw_class, tok::kw_enum, tok::kw_struct,
1694+
tok::kw_using)) {
16951695
return false;
16961696
}
16971697

clang/lib/Format/UnwrappedLineParser.cpp

Lines changed: 4 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -1818,9 +1818,6 @@ void UnwrappedLineParser::parseStructuralElement(
18181818
break;
18191819
}
18201820
break;
1821-
case tok::kw_concept:
1822-
parseConcept();
1823-
return;
18241821
case tok::kw_requires: {
18251822
if (Style.isCpp()) {
18261823
bool ParsedClause = parseRequires();
@@ -3277,26 +3274,6 @@ void UnwrappedLineParser::parseAccessSpecifier() {
32773274
}
32783275
}
32793276

3280-
/// \brief Parses a concept definition.
3281-
/// \pre The current token has to be the concept keyword.
3282-
///
3283-
/// Returns if either the concept has been completely parsed, or if it detects
3284-
/// that the concept definition is incorrect.
3285-
void UnwrappedLineParser::parseConcept() {
3286-
assert(FormatTok->is(tok::kw_concept) && "'concept' expected");
3287-
nextToken();
3288-
if (!FormatTok->is(tok::identifier))
3289-
return;
3290-
nextToken();
3291-
if (!FormatTok->is(tok::equal))
3292-
return;
3293-
nextToken();
3294-
parseConstraintExpression();
3295-
if (FormatTok->is(tok::semi))
3296-
nextToken();
3297-
addUnwrappedLine();
3298-
}
3299-
33003277
/// \brief Parses a requires, decides if it is a clause or an expression.
33013278
/// \pre The current token has to be the requires keyword.
33023279
/// \returns true if it parsed a clause.
@@ -3463,6 +3440,8 @@ void UnwrappedLineParser::parseRequiresClause(FormatToken *RequiresToken) {
34633440
? TT_RequiresClauseInARequiresExpression
34643441
: TT_RequiresClause);
34653442

3443+
// NOTE: parseConstraintExpression is only ever called from this function.
3444+
// It could be inlined into here.
34663445
parseConstraintExpression();
34673446

34683447
if (!InRequiresExpression)
@@ -3496,9 +3475,8 @@ void UnwrappedLineParser::parseRequiresExpression(FormatToken *RequiresToken) {
34963475

34973476
/// \brief Parses a constraint expression.
34983477
///
3499-
/// This is either the definition of a concept, or the body of a requires
3500-
/// clause. It returns, when the parsing is complete, or the expression is
3501-
/// incorrect.
3478+
/// This is the body of a requires clause. It returns, when the parsing is
3479+
/// complete, or the expression is incorrect.
35023480
void UnwrappedLineParser::parseConstraintExpression() {
35033481
// The special handling for lambdas is needed since tryToParseLambda() eats a
35043482
// token and if a requires expression is the last part of a requires clause

clang/lib/Format/UnwrappedLineParser.h

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -158,7 +158,6 @@ class UnwrappedLineParser {
158158
void parseAccessSpecifier();
159159
bool parseEnum();
160160
bool parseStructLike();
161-
void parseConcept();
162161
bool parseRequires();
163162
void parseRequiresClause(FormatToken *RequiresToken);
164163
void parseRequiresExpression(FormatToken *RequiresToken);

clang/unittests/Format/FormatTest.cpp

Lines changed: 22 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -23588,19 +23588,19 @@ TEST_F(FormatTest, Concepts) {
2358823588
"concept DelayedCheck = !!false || requires(T t) { t.bar(); } "
2358923589
"&& sizeof(T) <= 8;");
2359023590

23591-
verifyFormat(
23592-
"template <typename T>\n"
23593-
"concept DelayedCheck = static_cast<bool>(0) ||\n"
23594-
" requires(T t) { t.bar(); } && sizeof(T) <= 8;");
23591+
verifyFormat("template <typename T>\n"
23592+
"concept DelayedCheck =\n"
23593+
" static_cast<bool>(0) || requires(T t) { t.bar(); } && "
23594+
"sizeof(T) <= 8;");
2359523595

2359623596
verifyFormat("template <typename T>\n"
2359723597
"concept DelayedCheck = bool(0) || requires(T t) { t.bar(); } "
2359823598
"&& sizeof(T) <= 8;");
2359923599

2360023600
verifyFormat(
2360123601
"template <typename T>\n"
23602-
"concept DelayedCheck = (bool)(0) ||\n"
23603-
" requires(T t) { t.bar(); } && sizeof(T) <= 8;");
23602+
"concept DelayedCheck =\n"
23603+
" (bool)(0) || requires(T t) { t.bar(); } && sizeof(T) <= 8;");
2360423604

2360523605
verifyFormat("template <typename T>\n"
2360623606
"concept DelayedCheck = (bool)0 || requires(T t) { t.bar(); } "
@@ -23636,6 +23636,9 @@ TEST_F(FormatTest, Concepts) {
2363623636
verifyFormat("template <typename T>\n"
2363723637
"concept True = S<T>::Value;");
2363823638

23639+
verifyFormat("template <S T>\n"
23640+
"concept True = T.field;");
23641+
2363923642
verifyFormat(
2364023643
"template <typename T>\n"
2364123644
"concept C = []() { return true; }() && requires(T t) { t.bar(); } &&\n"
@@ -23914,11 +23917,9 @@ TEST_F(FormatTest, Concepts) {
2391423917
verifyFormat("template <typename T> concept True = true;", Style);
2391523918

2391623919
verifyFormat(
23917-
"template <typename T> concept C = decltype([]() -> std::true_type {\n"
23918-
" return {};\n"
23919-
" }())::value &&\n"
23920-
" requires(T t) { t.bar(); } && "
23921-
"sizeof(T) <= 8;",
23920+
"template <typename T> concept C =\n"
23921+
" decltype([]() -> std::true_type { return {}; }())::value &&\n"
23922+
" requires(T t) { t.bar(); } && sizeof(T) <= 8;",
2392223923
Style);
2392323924

2392423925
verifyFormat("template <typename T> concept Semiregular =\n"
@@ -23936,21 +23937,20 @@ TEST_F(FormatTest, Concepts) {
2393623937

2393723938
// The following tests are invalid C++, we just want to make sure we don't
2393823939
// assert.
23939-
verifyFormat("template <typename T>\n"
23940-
"concept C = requires C2<T>;");
23940+
verifyNoCrash("template <typename T>\n"
23941+
"concept C = requires C2<T>;");
2394123942

23942-
verifyFormat("template <typename T>\n"
23943-
"concept C = 5 + 4;");
23943+
verifyNoCrash("template <typename T>\n"
23944+
"concept C = 5 + 4;");
2394423945

23945-
verifyFormat("template <typename T>\n"
23946-
"concept C =\n"
23947-
"class X;");
23946+
verifyNoCrash("template <typename T>\n"
23947+
"concept C = class X;");
2394823948

23949-
verifyFormat("template <typename T>\n"
23950-
"concept C = [] && true;");
23949+
verifyNoCrash("template <typename T>\n"
23950+
"concept C = [] && true;");
2395123951

23952-
verifyFormat("template <typename T>\n"
23953-
"concept C = [] && requires(T t) { typename T::size_type; };");
23952+
verifyNoCrash("template <typename T>\n"
23953+
"concept C = [] && requires(T t) { typename T::size_type; };");
2395423954
}
2395523955

2395623956
TEST_F(FormatTest, RequiresClausesPositions) {

0 commit comments

Comments
 (0)