Skip to content

Commit

Permalink
[clang] Error on substitution failure within lambda body inside a req…
Browse files Browse the repository at this point in the history
…uires-expression

Per CWG 2672 substitution failure within the body of a lambda inside a
requires-expression should be a hard error.

Fixes #64138

Reviewed By: cor3ntin

Differential Revision: https://reviews.llvm.org/D156993
  • Loading branch information
Fznamznon committed Aug 8, 2023
1 parent 5753103 commit 38cf47f
Show file tree
Hide file tree
Showing 5 changed files with 39 additions and 12 deletions.
4 changes: 4 additions & 0 deletions clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -157,6 +157,10 @@ Bug Fixes to C++ Support
(`#35574 <https://github.com/llvm/llvm-project/issues/35574>_`) and
(`#27224 <https://github.com/llvm/llvm-project/issues/27224>_`).

- Clang emits an error on substitution failure within lambda body inside a
requires-expression. This fixes:
(`#64138 <https://github.com/llvm/llvm-project/issues/64138>_`).

Bug Fixes to AST Handling
^^^^^^^^^^^^^^^^^^^^^^^^^
- Fixed an import failure of recursive friend class template.
Expand Down
9 changes: 2 additions & 7 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1074,7 +1074,6 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
if (InNonInstantiationSFINAEContext)
return std::optional<TemplateDeductionInfo *>(nullptr);

bool SawLambdaSubstitution = false;
for (SmallVectorImpl<CodeSynthesisContext>::const_reverse_iterator
Active = CodeSynthesisContexts.rbegin(),
ActiveEnd = CodeSynthesisContexts.rend();
Expand All @@ -1101,10 +1100,8 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
// A lambda-expression appearing in a function type or a template
// parameter is not considered part of the immediate context for the
// purposes of template argument deduction.

// We need to check parents.
SawLambdaSubstitution = true;
break;
// CWG2672: A lambda-expression body is never in the immediate context.
return std::nullopt;

case CodeSynthesisContext::DefaultTemplateArgumentInstantiation:
case CodeSynthesisContext::PriorTemplateArgumentSubstitution:
Expand All @@ -1120,8 +1117,6 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
// We're either substituting explicitly-specified template arguments,
// deduced template arguments. SFINAE applies unless we are in a lambda
// expression, see [temp.deduct]p9.
if (SawLambdaSubstitution)
return std::nullopt;
[[fallthrough]];
case CodeSynthesisContext::ConstraintSubstitution:
case CodeSynthesisContext::RequirementInstantiation:
Expand Down
21 changes: 21 additions & 0 deletions clang/test/CXX/drs/dr26xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -150,3 +150,24 @@ static_assert(__is_same(decltype(i), I<char, 4>));

J j = { "ghi" }; // expected-error {{no viable constructor or deduction guide}}
}

namespace dr2672 { // dr2672: 18 open
template <class T>
void f(T) requires requires { []() { T::invalid; } (); }; // expected-error{{type 'int' cannot be used prior to '::'}}
// expected-note@-1{{while substituting into a lambda expression here}}
// expected-note@-2{{in instantiation of requirement here}}
// expected-note@-3{{while substituting template arguments into constraint expression here}}
void f(...);

template <class T>
void bar(T) requires requires {
decltype([]() -> T {})::foo();
};
void bar(...);

void m() {
f(0); // expected-note {{while checking constraint satisfaction for template 'f<int>' required here}}
// expected-note@-1 {{in instantiation of function template specialization}}
bar(0);
}
}
15 changes: 11 additions & 4 deletions clang/test/SemaCXX/lambda-unevaluated.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -155,17 +155,24 @@ struct WithFoo { static void foo(); };

template <class T>
concept lambda_works = requires {
[]() { T::foo(); };
[]() { T::foo(); }; // expected-error{{type 'int' cannot be used prior to '::'}}
// expected-note@-1{{while substituting into a lambda expression here}}
// expected-note@-2{{in instantiation of requirement here}}
// expected-note@-4{{while substituting template arguments into constraint expression here}}
};

static_assert(!lambda_works<int>);
static_assert(!lambda_works<int>); // expected-note {{while checking the satisfaction of concept 'lambda_works<int>' requested here}}
static_assert(lambda_works<WithFoo>);

template <class T>
int* func(T) requires requires { []() { T::foo(); }; };
int* func(T) requires requires { []() { T::foo(); }; }; // expected-error{{type 'int' cannot be used prior to '::'}}
// expected-note@-1{{while substituting into a lambda expression here}}
// expected-note@-2{{in instantiation of requirement here}}
// expected-note@-3{{while substituting template arguments into constraint expression here}}
double* func(...);

static_assert(__is_same(decltype(func(0)), double*));
static_assert(__is_same(decltype(func(0)), double*)); // expected-note {{while checking constraint satisfaction for template 'func<int>' required here}}
// expected-note@-1 {{in instantiation of function template specialization 'lambda_in_constraints::func<int>'}}
static_assert(__is_same(decltype(func(WithFoo())), int*));

template <class T>
Expand Down
2 changes: 1 addition & 1 deletion clang/www/cxx_dr_status.html
Original file line number Diff line number Diff line change
Expand Up @@ -15839,7 +15839,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2672.html">2672</a></td>
<td>open</td>
<td>Lambda body SFINAE is still required, contrary to intent and note</td>
<td align="center">Not resolved</td>
<td class="unreleased" align="center">Clang 18</td>
</tr>
<tr id="2673">
<td><a href="https://cplusplus.github.io/CWG/issues/2673.html">2673</a></td>
Expand Down

0 comments on commit 38cf47f

Please sign in to comment.