diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -132,6 +132,10 @@ (`#35574 _`) and (`#27224 _`). +- Clang emits an error on substitution failure within lambda body inside a + requires-expression. This fixes: + (`#64138 _`). + Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ - Fixed an import failure of recursive friend class template. diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1074,7 +1074,6 @@ if (InNonInstantiationSFINAEContext) return std::optional(nullptr); - bool SawLambdaSubstitution = false; for (SmallVectorImpl::const_reverse_iterator Active = CodeSynthesisContexts.rbegin(), ActiveEnd = CodeSynthesisContexts.rend(); @@ -1101,10 +1100,7 @@ // 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; + return std::nullopt; case CodeSynthesisContext::DefaultTemplateArgumentInstantiation: case CodeSynthesisContext::PriorTemplateArgumentSubstitution: @@ -1120,8 +1116,6 @@ // 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: diff --git a/clang/test/SemaCXX/lambda-unevaluated.cpp b/clang/test/SemaCXX/lambda-unevaluated.cpp --- a/clang/test/SemaCXX/lambda-unevaluated.cpp +++ b/clang/test/SemaCXX/lambda-unevaluated.cpp @@ -155,17 +155,24 @@ template 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); +static_assert(!lambda_works); // expected-note {{while checking the satisfaction of concept 'lambda_works' requested here}} static_assert(lambda_works); template -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' required here}} + // expected-note@-1 {{in instantiation of function template specialization 'lambda_in_constraints::func'}} static_assert(__is_same(decltype(func(WithFoo())), int*)); template