[clang] 6acdf58 - [clang] Properly parse variable template requires clause in lambda
Emilia Dreamer via cfe-commits
cfe-commits at lists.llvm.org
Fri Mar 17 13:31:54 PDT 2023
Author: Emilia Dreamer
Date: 2023-03-17T22:29:48+02:00
New Revision: 6acdf58919d5e66809555acf5809b12c54ba79dd
URL: https://github.com/llvm/llvm-project/commit/6acdf58919d5e66809555acf5809b12c54ba79dd
DIFF: https://github.com/llvm/llvm-project/commit/6acdf58919d5e66809555acf5809b12c54ba79dd.diff
LOG: [clang] Properly parse variable template requires clause in lambda
Since P0857, part of C++20, a *lambda-expression* can contain a
*requires-clause* after its *template-parameter-list*.
While support for this was added as part of
eccc734a69c0c012ae3160887b65a535b35ead3e, one specific case isn't
handled properly, where the *requires-clause* consists of an
instantiation of a boolean variable template. This is due to a
diagnostic check which was written with the assumption that a
*requires-clause* can never be followed by a left parenthesis. This
assumption no longer holds for lambdas.
This diagnostic check would then attempt to perform a "recovery", but it
does so in a valid parse state, resulting in an invalid parse state
instead!
This patch adds a special case when parsing requires clauses of lambda
templates, to skip this diagnostic check.
Fixes https://github.com/llvm/llvm-project/issues/61278
Fixes https://github.com/llvm/llvm-project/issues/61387
Reviewed By: erichkeane
Differential Revision: https://reviews.llvm.org/D146140
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/lib/Sema/SemaConcept.cpp
clang/test/SemaTemplate/concepts.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 24f5b622249d8..53001f651ea4b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -80,6 +80,9 @@ C++20 Feature Support
^^^^^^^^^^^^^^^^^^^^^
- Support for out-of-line definitions of constrained templates has been improved.
This partially fixes `#49620 <https://github.com/llvm/llvm-project/issues/49620>`_.
+- Lambda templates with a requires clause directly after the template parameters now parse
+ correctly if the requires clause consists of a variable with a dependent type.
+ (`#61278 <https://github.com/llvm/llvm-project/issues/61278>`_)
C++2b Feature Support
^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp
index 4a795227e6293..4ff86843dacc1 100644
--- a/clang/lib/Sema/SemaConcept.cpp
+++ b/clang/lib/Sema/SemaConcept.cpp
@@ -105,27 +105,35 @@ bool Sema::CheckConstraintExpression(const Expr *ConstraintExpression,
QualType Type = ConstraintExpression->getType();
auto CheckForNonPrimary = [&] {
- if (PossibleNonPrimary)
- *PossibleNonPrimary =
- // We have the following case:
- // template<typename> requires func(0) struct S { };
- // The user probably isn't aware of the parentheses required around
- // the function call, and we're only going to parse 'func' as the
- // primary-expression, and complain that it is of non-bool type.
- (NextToken.is(tok::l_paren) &&
- (IsTrailingRequiresClause ||
- (Type->isDependentType() &&
- isa<UnresolvedLookupExpr>(ConstraintExpression)) ||
- Type->isFunctionType() ||
- Type->isSpecificBuiltinType(BuiltinType::Overload))) ||
- // We have the following case:
- // template<typename T> requires size_<T> == 0 struct S { };
- // The user probably isn't aware of the parentheses required around
- // the binary operator, and we're only going to parse 'func' as the
- // first operand, and complain that it is of non-bool type.
- getBinOpPrecedence(NextToken.getKind(),
- /*GreaterThanIsOperator=*/true,
- getLangOpts().CPlusPlus11) > prec::LogicalAnd;
+ if (!PossibleNonPrimary)
+ return;
+
+ *PossibleNonPrimary =
+ // We have the following case:
+ // template<typename> requires func(0) struct S { };
+ // The user probably isn't aware of the parentheses required around
+ // the function call, and we're only going to parse 'func' as the
+ // primary-expression, and complain that it is of non-bool type.
+ //
+ // However, if we're in a lambda, this might also be:
+ // []<typename> requires var () {};
+ // Which also looks like a function call due to the lambda parentheses,
+ // but unlike the first case, isn't an error, so this check is skipped.
+ (NextToken.is(tok::l_paren) &&
+ (IsTrailingRequiresClause ||
+ (Type->isDependentType() &&
+ isa<UnresolvedLookupExpr>(ConstraintExpression) &&
+ !dyn_cast_if_present<LambdaScopeInfo>(getCurFunction())) ||
+ Type->isFunctionType() ||
+ Type->isSpecificBuiltinType(BuiltinType::Overload))) ||
+ // We have the following case:
+ // template<typename T> requires size_<T> == 0 struct S { };
+ // The user probably isn't aware of the parentheses required around
+ // the binary operator, and we're only going to parse 'func' as the
+ // first operand, and complain that it is of non-bool type.
+ getBinOpPrecedence(NextToken.getKind(),
+ /*GreaterThanIsOperator=*/true,
+ getLangOpts().CPlusPlus11) > prec::LogicalAnd;
};
// An atomic constraint!
diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp
index df4db9b8d4457..bf5896a14991b 100644
--- a/clang/test/SemaTemplate/concepts.cpp
+++ b/clang/test/SemaTemplate/concepts.cpp
@@ -55,10 +55,15 @@ namespace PR45699 {
}
namespace P0857R0 {
+ template <typename T> static constexpr bool V = true;
+
void f() {
auto x = []<bool B> requires B {}; // expected-note {{constraints not satisfied}} expected-note {{false}}
x.operator()<true>();
x.operator()<false>(); // expected-error {{no matching member function}}
+
+ auto y = []<typename T> requires V<T> () {};
+ y.operator()<int>(); // OK
}
template<typename T> concept C = true;
More information about the cfe-commits
mailing list