diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -80,6 +80,9 @@ ^^^^^^^^^^^^^^^^^^^^^ - Support for out-of-line definitions of constrained templates has been improved. This partially fixes `#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 `_) C++2b Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Sema/SemaConcept.cpp b/clang/lib/Sema/SemaConcept.cpp --- a/clang/lib/Sema/SemaConcept.cpp +++ b/clang/lib/Sema/SemaConcept.cpp @@ -105,27 +105,35 @@ QualType Type = ConstraintExpression->getType(); auto CheckForNonPrimary = [&] { - if (PossibleNonPrimary) - *PossibleNonPrimary = - // We have the following case: - // template 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(ConstraintExpression)) || - Type->isFunctionType() || - Type->isSpecificBuiltinType(BuiltinType::Overload))) || - // We have the following case: - // template requires size_ == 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 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: + // [] 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(ConstraintExpression) && + !dyn_cast_if_present(getCurFunction())) || + Type->isFunctionType() || + Type->isSpecificBuiltinType(BuiltinType::Overload))) || + // We have the following case: + // template requires size_ == 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 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -55,10 +55,15 @@ } namespace P0857R0 { + template static constexpr bool V = true; + void f() { auto x = [] requires B {}; // expected-note {{constraints not satisfied}} expected-note {{false}} x.operator()(); x.operator()(); // expected-error {{no matching member function}} + + auto y = [] requires V () {}; + y.operator()(); // OK } template concept C = true;