diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index d3d731cf9d438..4ec4e4a49de6b 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -91,6 +91,9 @@ C++20 Feature Support building of standard modules. This diagnostic may be strengthened into an error again in the future once there is a less fragile way to mark a module as being part of the implementation rather than a user module. +- Clang now implements `[temp.deduct]p9`. Substitution failures inside lambdas from + unevaluated contexts will be surfaced as errors. They were previously handled as + SFINAE. C++23 Feature Support ^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td index bade9ad5d5be3..e6b2e28a82ded 100644 --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -5327,6 +5327,8 @@ def note_constraint_normalization_here : Note< def note_parameter_mapping_substitution_here : Note< "while substituting into concept arguments here; substitution failures not " "allowed in concept arguments">; +def note_lambda_substitution_here : Note< + "while substituting into a lambda expression here">; def note_instantiation_contexts_suppressed : Note< "(skipping %0 context%s0 in backtrace; use -ftemplate-backtrace-limit=0 to " "see all)">; diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index f65f8e3f2b50b..5296d7000b5cc 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -9261,6 +9261,9 @@ class Sema final { /// a TemplateDecl. DeducedTemplateArgumentSubstitution, + /// We are substituting into a lambda expression. + LambdaExpressionSubstitution, + /// We are substituting prior template arguments into a new /// template parameter. The template parameter itself is either a /// NonTypeTemplateParmDecl or a TemplateTemplateParmDecl. diff --git a/clang/lib/Frontend/FrontendActions.cpp b/clang/lib/Frontend/FrontendActions.cpp index c947772ec3e70..f62a29c02ee13 100644 --- a/clang/lib/Frontend/FrontendActions.cpp +++ b/clang/lib/Frontend/FrontendActions.cpp @@ -372,6 +372,8 @@ class DefaultTemplateInstCallback : public TemplateInstantiationCallback { return "ExplicitTemplateArgumentSubstitution"; case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: return "DeducedTemplateArgumentSubstitution"; + case CodeSynthesisContext::LambdaExpressionSubstitution: + return "LambdaExpressionSubstitution"; case CodeSynthesisContext::PriorTemplateArgumentSubstitution: return "PriorTemplateArgumentSubstitution"; case CodeSynthesisContext::DefaultTemplateArgumentChecking: diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 1582a5c4b6e44..a25f8175ebcdb 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -35,6 +35,7 @@ #include "clang/Sema/Template.h" #include "clang/Sema/TemplateDeduction.h" #include "clang/Sema/TemplateInstCallback.h" +#include "llvm/ADT/ScopeExit.h" #include "llvm/Support/ErrorHandling.h" #include "llvm/Support/TimeProfiler.h" #include @@ -368,6 +369,7 @@ bool Sema::CodeSynthesisContext::isInstantiationRecord() const { case InitializingStructuredBinding: case MarkingClassDllexported: case BuildingBuiltinDumpStructCall: + case LambdaExpressionSubstitution: return false; // This function should never be called when Kind's value is Memoization. @@ -962,6 +964,10 @@ void Sema::PrintInstantiationStack() { case CodeSynthesisContext::Memoization: break; + case CodeSynthesisContext::LambdaExpressionSubstitution: + Diags.Report(Active->PointOfInstantiation, + diag::note_lambda_substitution_here); + break; case CodeSynthesisContext::ConstraintsCheck: { unsigned DiagID = 0; if (!Active->Entity) { @@ -1017,6 +1023,7 @@ std::optional Sema::isSFINAEContext() const { if (InNonInstantiationSFINAEContext) return std::optional(nullptr); + bool SawLambdaSubstitution = false; for (SmallVectorImpl::const_reverse_iterator Active = CodeSynthesisContexts.rbegin(), ActiveEnd = CodeSynthesisContexts.rend(); @@ -1038,6 +1045,15 @@ std::optional Sema::isSFINAEContext() const { case CodeSynthesisContext::NestedRequirementConstraintsCheck: // This is a template instantiation, so there is no SFINAE. return std::nullopt; + case CodeSynthesisContext::LambdaExpressionSubstitution: + // [temp.deduct]p9 + // 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; case CodeSynthesisContext::DefaultTemplateArgumentInstantiation: case CodeSynthesisContext::PriorTemplateArgumentSubstitution: @@ -1050,12 +1066,17 @@ std::optional Sema::isSFINAEContext() const { case CodeSynthesisContext::ExplicitTemplateArgumentSubstitution: case CodeSynthesisContext::DeducedTemplateArgumentSubstitution: + // 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: case CodeSynthesisContext::RequirementParameterInstantiation: - // We're either substituting explicitly-specified template arguments, - // deduced template arguments, a constraint expression or a requirement - // in a requires expression, so SFINAE applies. + // SFINAE always applies in a constraint expression or a requirement + // in a requires expression. assert(Active->DeductionInfo && "Missing deduction info pointer"); return Active->DeductionInfo; @@ -1344,6 +1365,14 @@ namespace { ExprResult TransformLambdaExpr(LambdaExpr *E) { LocalInstantiationScope Scope(SemaRef, /*CombineWithOuterScope=*/true); Sema::ConstraintEvalRAII RAII(*this); + + Sema::CodeSynthesisContext C; + C.Kind = clang::Sema::CodeSynthesisContext::LambdaExpressionSubstitution; + C.PointOfInstantiation = E->getBeginLoc(); + SemaRef.pushCodeSynthesisContext(C); + auto PopCtx = + llvm::make_scope_exit([this] { SemaRef.popCodeSynthesisContext(); }); + ExprResult Result = inherited::TransformLambdaExpr(E); if (Result.isInvalid()) return Result; diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp index 72265d77700aa..c5d08ec404a7c 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp @@ -35,7 +35,8 @@ struct NoDefaultCtor { template void defargs_in_template_unused(T t) { auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \ - // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} + // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} \ + // expected-note {{while substituting into a lambda expression here}} l1(t); } @@ -45,7 +46,8 @@ template void defargs_in_template_unused(NoDefaultCtor); // expected-note{{in i template void defargs_in_template_used() { auto l1 = [](const T& value = T()) { }; // expected-error{{no matching constructor for initialization of 'NoDefaultCtor'}} \ - // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} + // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} \ + // expected-note {{while substituting into a lambda expression here}} l1(); } diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp index 67953c6a6f901..ed36a33850ce4 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp @@ -35,6 +35,7 @@ auto init_kind_2 = [ec = ExplicitCopy()] {}; // expected-error {{no matching con template void init_kind_template() { auto init_kind_1 = [ec(T())] {}; auto init_kind_2 = [ec = T()] {}; // expected-error {{no matching constructor}} + // expected-note@-1 {{while substituting into a lambda expression here}} } template void init_kind_template(); template void init_kind_template(); // expected-note {{instantiation of}} @@ -52,6 +53,7 @@ auto bad_init_6 = [a{overload_fn}] {}; // expected-error {{cannot deduce type fo auto bad_init_7 = [a{{1}}] {}; // expected-error {{cannot deduce type for lambda capture 'a' from nested initializer list}} template void pack_1(T...t) { (void)[a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}} + // expected-note@-1 {{while substituting into a lambda expression here}} template void pack_1<>(); // expected-note {{instantiation of}} // No lifetime-extension of the temporary here. @@ -74,6 +76,7 @@ auto s = [s(move(S()))] {}; template T instantiate_test(T t) { [x(&t)]() { *x = 1; } (); // expected-error {{assigning to 'const char *'}} + // expected-note@-1 {{while substituting into a lambda expression here}} return t; } int instantiate_test_1 = instantiate_test(0); diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp index 028fcee5fda43..a5278c27bf25c 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp @@ -85,6 +85,7 @@ void init_capture_pack_err(Args ...args) { template void init_capture_pack_multi(Args ...args) { [as(args...)] {} (); // expected-error {{initializer missing for lambda capture 'as'}} expected-error {{multiple}} + // expected-note@-1 2{{while substituting into a lambda expression}} } template void init_capture_pack_multi(); // expected-note {{instantiation}} template void init_capture_pack_multi(int); diff --git a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp index 660f6091bb663..ffac9112491fe 100644 --- a/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp +++ b/clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp @@ -54,6 +54,7 @@ void test_result_type(int N) { template void test_result_type_tpl(int N) { auto l1 = []() -> T {}; // expected-error{{incomplete result type 'Incomplete' in lambda expression}} + // expected-note@-1{{while substituting into a lambda expression here}} typedef int vla[N]; auto l2 = []() -> vla {}; // expected-error{{function cannot return array type 'vla' (aka 'int[N]')}} } diff --git a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp index 6579eb19a7596..0c357db764a92 100644 --- a/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp +++ b/clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp @@ -80,6 +80,7 @@ namespace generic_lambda { [](auto x) { if constexpr (sizeof(T) == 1 && sizeof(x) == 1) T::error(); // expected-error 2{{'::'}} + // expected-note@-3 2{{while substituting into a lambda expression here}} } (0); } @@ -88,6 +89,7 @@ namespace generic_lambda { if constexpr (sizeof(T) == 1) if constexpr (sizeof(x) == 1) T::error(); // expected-error {{'::'}} + // expected-note@-4 {{while substituting into a lambda expression here}} } (0); } diff --git a/clang/test/CXX/temp/temp.deduct/p9.cpp b/clang/test/CXX/temp/temp.deduct/p9.cpp new file mode 100644 index 0000000000000..23bcd2a1892e7 --- /dev/null +++ b/clang/test/CXX/temp/temp.deduct/p9.cpp @@ -0,0 +1,56 @@ +// RUN: %clang_cc1 -std=c++20 -verify %s +// [temp.deduct.p9] +// 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. +// [Note: The intent is to avoid requiring implementations to deal with +// substitution failure involving arbitrary statements.] +template +auto f(T) -> decltype([]() { T::invalid; } ()); +void f(...); +void test_f() { + f(0); // expected-error@-3 {{type 'int' cannot be used prior to '::'}} + // expected-note@-1 {{while substituting deduced template arguments}} + // expected-note@-5 {{while substituting into a lambda expression here}} +} + +template +void g(T); +void g(...); +void test_g() { + g(0); // expected-error@-4 {{type 'int' cannot be used prior to '::'}} + // expected-note@-4 {{in instantiation of default argument}} + // expected-note@-2 {{while substituting deduced template arguments}} + // expected-note@-7 {{while substituting into a lambda expression here}} +} + +template +auto h(T) -> decltype([x = T::invalid]() { }); +void h(...); +void test_h() { + h(0); // expected-error@-3 {{type 'int' cannot be used prior to '::'}} + // expected-note@-1 {{while substituting deduced template arguments}} + // expected-note@-5 {{while substituting into a lambda expression here}} +} + +template +auto i(T) -> decltype([]() -> typename T::invalid { }); +void i(...); +void test_i() { + i(0); // expected-error@-3 {{type 'int' cannot be used prior to '::'}} + // expected-note@-1 {{while substituting deduced template arguments}} + // expected-note@-5 {{while substituting into a lambda expression here}} +} + + +// In this example, the lambda itself is not part of an immediate context, but +// substitution to the lambda expression succeeds, producing dependent +// `decltype(x.invalid)`. The call to the lambda, however, is in the immediate context +// and it produces a SFINAE failure. Hence, we pick the second overload +// and don't produce any errors. +template +auto j(T t) -> decltype([](auto x) -> decltype(x.invalid) { } (t)); // #1 +void j(...); // #2 +void test_j() { + j(0); // deduction fails on #1, calls #2. +} diff --git a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp index 63f56640b1ce9..83144a494937b 100644 --- a/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp +++ b/clang/test/CXX/temp/temp.param/p15-cxx0x.cpp @@ -141,6 +141,7 @@ template struct A { B() { consume([]{ int arr[Vs]; // expected-error {{negative size}} + // expected-note@-2 {{while substituting into a lambda expression here}} }...); } }; diff --git a/clang/test/PCH/cxx1y-init-captures.cpp b/clang/test/PCH/cxx1y-init-captures.cpp index 7f8a9fa4b3c1d..c19dd90ac90be 100644 --- a/clang/test/PCH/cxx1y-init-captures.cpp +++ b/clang/test/PCH/cxx1y-init-captures.cpp @@ -25,6 +25,7 @@ int y = counter(); void g() { f(0); // ok // expected-error@18 {{lvalue of type 'const char *const'}} + // expected-note@18 {{substituting into a lambda}} f("foo"); // expected-note {{here}} } diff --git a/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp index e9e2ecab8e028..dcc964cd60b34 100644 --- a/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp +++ b/clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp @@ -563,8 +563,8 @@ struct X { int g() { auto L = [=](auto a) { - return [](int i) { // expected-note {{explicitly capture 'this'}} - return [=](auto b) { + return [](int i) { // expected-note {{explicitly capture 'this'}} expected-note {{while substituting into a lambda}} + return [=](auto b) { // expected-note {{while substituting into a lambda}} f(decltype(a){}); //expected-error{{this}} int x = i; }; @@ -587,8 +587,8 @@ struct X { int g() { auto L = [=](auto a) { - return [](auto b) { // expected-note {{explicitly capture 'this'}} - return [=](int i) { + return [](auto b) { // expected-note {{explicitly capture 'this'}} expected-note {{while substituting into a lambda}} + return [=](int i) { // expected-note {{while substituting into a lambda}} f(b); f(decltype(a){}); //expected-error{{this}} }; @@ -612,7 +612,7 @@ struct X { int g() { auto L = [=](auto a) { return [](auto b) { // expected-note {{explicitly capture 'this'}} - return [=](int i) { + return [=](int i) { // expected-note {{while substituting into a lambda}} f(b); //expected-error{{this}} f(decltype(a){}); }; diff --git a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp index 61dfd654f6d65..3c2d460ab9b4a 100644 --- a/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp +++ b/clang/test/SemaCXX/cxx1y-generic-lambdas.cpp @@ -259,7 +259,7 @@ int test() { { int i = 10; //expected-note 3{{declared here}} auto L = [](auto a) { - return [](auto b) { //expected-note 3{{begins here}} expected-note 6 {{capture 'i' by}} expected-note 6 {{default capture by}} + return [](auto b) { //expected-note 3{{begins here}} expected-note 6 {{capture 'i' by}} expected-note 6 {{default capture by}} expected-note {{while substituting into a lambda}} i = b; //expected-error 3{{cannot be implicitly captured}} return b; }; diff --git a/clang/test/SemaCXX/cxx1y-init-captures.cpp b/clang/test/SemaCXX/cxx1y-init-captures.cpp index 1c1c93c757a0d..4cb53cc8bfc1c 100644 --- a/clang/test/SemaCXX/cxx1y-init-captures.cpp +++ b/clang/test/SemaCXX/cxx1y-init-captures.cpp @@ -21,17 +21,17 @@ namespace variadic_expansion { return a; }() ...); }; - auto N2 = [x = y, //expected-note3{{begins here}} expected-note 6 {{default capture by}} + auto N2 = [x = y, //expected-note3{{begins here}} expected-note 6 {{default capture by}} expected-note 2 {{substituting into a lambda}} &z = y, n = f(t...), o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) { // expected-note 6 {{capture 't' by}} - fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}} + fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}} expected-note 2{{substituting into a lambda}} return a; }() ...); }; } - void h(int i, char c) { g(i, c); } //expected-note{{in instantiation}} + void h(int i, char c) { g(i, c); } //expected-note 2{{in instantiation}} } namespace odr_use_within_init_capture { @@ -117,7 +117,7 @@ int test(T t = T{}) { } { // will need to capture x in outer lambda const T x = 10; //expected-note {{declared}} - auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}} + auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}} expected-note {{substituting into a lambda}} auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}} return y; }; @@ -145,7 +145,7 @@ int test(T t = T{}) { } { // will need to capture x in outer lambda const int x = 10; //expected-note {{declared}} - auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}} + auto L = [z = x](char a) { //expected-note {{begins}} expected-note 2 {{capture 'x' by}} expected-note 2 {{default capture by}} expected-note {{substituting into a lambda}} auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}} return y; }; @@ -164,7 +164,7 @@ int test(T t = T{}) { return 0; } -int run = test(); //expected-note {{instantiation}} +int run = test(); //expected-note 2 {{instantiation}} } diff --git a/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp b/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp index 95bc32b603ddf..0cee41ff5ed38 100644 --- a/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp +++ b/clang/test/SemaCXX/cxx1z-lambda-star-this.cpp @@ -46,7 +46,7 @@ class B { template void foo() { (void)[this] { return x; }; - (void)[*this] { return x; }; //expected-error2{{call to deleted}} + (void)[*this] { return x; }; //expected-error2{{call to deleted}} expected-note {{while substituting into a lambda}} } B() = default; @@ -63,7 +63,7 @@ class B { public: template auto foo() { - const auto &L = [*this](auto a) mutable { //expected-error{{call to deleted}} + const auto &L = [*this](auto a) mutable { //expected-error{{call to deleted}} expected-note {{while substituting into a lambda}} d += a; return [this](auto b) { return d += b; }; }; diff --git a/clang/test/SemaCXX/cxx20-decomposition.cpp b/clang/test/SemaCXX/cxx20-decomposition.cpp index 34f46f866c7df..430a158ff458e 100644 --- a/clang/test/SemaCXX/cxx20-decomposition.cpp +++ b/clang/test/SemaCXX/cxx20-decomposition.cpp @@ -177,7 +177,8 @@ namespace ODRUseTests { (void)[&b](auto c) { return b + [](auto) { // expected-note 3{{lambda expression begins here}} \ // expected-note 6{{capture 'a'}} \ // expected-note 6{{default capture}} \ - // expected-note {{in instantiation}} + // expected-note {{in instantiation}} \ + // expected-note {{while substituting into a lambda}} return a; // expected-error 3{{variable 'a' cannot be implicitly captured}} }(0); }(0); // expected-note 2{{in instantiation}} } diff --git a/clang/test/SemaCXX/lambda-expressions.cpp b/clang/test/SemaCXX/lambda-expressions.cpp index aeecf2109beff..b186583a7d82b 100644 --- a/clang/test/SemaCXX/lambda-expressions.cpp +++ b/clang/test/SemaCXX/lambda-expressions.cpp @@ -260,10 +260,11 @@ namespace VariadicPackExpansion { f([&ts] { return (int)f(ts...); } ()...); // \ // expected-error 2{{'ts' cannot be implicitly captured}} \ // expected-note 2{{lambda expression begins here}} \ - // expected-note 4 {{capture 'ts' by}} + // expected-note 4 {{capture 'ts' by}} \ + // expected-note 2 {{while substituting into a lambda}} } template void nested2(int); // ok - template void nested2(int, int); // expected-note {{in instantiation of}} + template void nested2(int, int); // expected-note 2 {{in instantiation of}} } namespace PR13860 { @@ -383,7 +384,7 @@ namespace PR18128 { namespace PR18473 { template void f() { T t(0); - (void) [=]{ int n = t; }; // expected-error {{deleted}} + (void) [=]{ int n = t; }; // expected-error {{deleted}} expected-note {{while substituting into a lambda}} } template void f(); @@ -466,7 +467,7 @@ namespace error_in_transform_prototype { void f(T t) { // expected-error@+2 {{type 'int' cannot be used prior to '::' because it has no members}} // expected-error@+1 {{no member named 'ns' in 'error_in_transform_prototype::S'}} - auto x = [](typename T::ns::type &k) {}; + auto x = [](typename T::ns::type &k) {}; // expected-note 2 {{while substituting into a lambda}} } class S {}; void foo() { diff --git a/clang/test/SemaCXX/lambda-pack-expansion.cpp b/clang/test/SemaCXX/lambda-pack-expansion.cpp index e3e968e2704ed..936e7c6b0e5c5 100644 --- a/clang/test/SemaCXX/lambda-pack-expansion.cpp +++ b/clang/test/SemaCXX/lambda-pack-expansion.cpp @@ -8,6 +8,7 @@ struct X { void take_by_copy(auto &...args) { [...args = args] {}(); // expected-error {{call to deleted constructor}} + // expected-note@-1 {{substituting into a lambda}} } void take_by_ref(auto &...args) { diff --git a/clang/test/SemaCXX/lambda-unevaluated.cpp b/clang/test/SemaCXX/lambda-unevaluated.cpp index 135c6f6bfc05e..179c7327ebdff 100644 --- a/clang/test/SemaCXX/lambda-unevaluated.cpp +++ b/clang/test/SemaCXX/lambda-unevaluated.cpp @@ -28,8 +28,11 @@ static_assert(&unique_test1<[](){}> != &unique_test1<[](){}>); template auto g(T) -> decltype([]() { T::invalid; } ()); -auto e = g(0); // expected-error{{no matching function for call}} -// expected-note@-2 {{substitution failure}} +auto e = g(0); // expected-error@-1{{type 'int' cannot be used prior to '::'}} + // expected-note@-1{{while substituting deduced template}} + // expected-note@-3{{while substituting into a lambda}} + // expected-error@-3 {{no matching function for call to 'g'}} + // expected-note@-5 {{substitution failure}} template auto foo(decltype([] { @@ -146,3 +149,36 @@ using d = decltype(sizeof([] static { return 0; })); namespace lambda_in_trailing_decltype { auto x = ([](auto) -> decltype([] {}()) {}(0), 2); } + +namespace lambda_in_constraints { +struct WithFoo { static void foo(); }; + +template +concept lambda_works = requires { + []() { T::foo(); }; +}; + +static_assert(!lambda_works); +static_assert(lambda_works); + +template +int* func(T) requires requires { []() { T::foo(); }; }; +double* func(...); + +static_assert(__is_same(decltype(func(0)), double*)); +static_assert(__is_same(decltype(func(WithFoo())), int*)); + +template +auto direct_lambda(T) -> decltype([] { T::foo(); }) {} +void direct_lambda(...) {} + +void recursive() { + direct_lambda(0); // expected-error@-4 {{type 'int' cannot be used prior to '::'}} + // expected-note@-1 {{while substituting deduced template arguments}} + // expected-note@-6 {{while substituting into a lambda}} + bool x = requires { direct_lambda(0); }; // expected-error@-7 {{type 'int' cannot be used prior to '::'}} + // expected-note@-1 {{while substituting deduced template arguments}} + // expected-note@-9 {{while substituting into a lambda}} + +} +} diff --git a/clang/test/SemaCXX/vartemplate-lambda.cpp b/clang/test/SemaCXX/vartemplate-lambda.cpp index 8b232abe976b6..d2b53b53dcd49 100644 --- a/clang/test/SemaCXX/vartemplate-lambda.cpp +++ b/clang/test/SemaCXX/vartemplate-lambda.cpp @@ -8,6 +8,7 @@ template auto v1 = [](int a = T()) { return a; }(); // expected-error@-1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}} // expected-note@-2{{in instantiation of default function argument expression for 'operator()' required here}} // expected-note@-3{{passing argument to parameter 'a' here}} +// expected-note@-4{{substituting into a lambda}} struct S { template diff --git a/clang/test/SemaCXX/warn-unused-lambda-capture.cpp b/clang/test/SemaCXX/warn-unused-lambda-capture.cpp index 52ec390b0bba6..67b8fc3b661c8 100644 --- a/clang/test/SemaCXX/warn-unused-lambda-capture.cpp +++ b/clang/test/SemaCXX/warn-unused-lambda-capture.cpp @@ -145,38 +145,38 @@ void test_templated() { auto explicit_by_value_used_generic = [i](auto c) { return i + 1; }; auto explicit_by_value_used_void = [i] { (void)i; }; - auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} - auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}} - auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}} - auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}} - auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}} + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}} + auto explicit_by_value_unused_sizeof = [i] { return sizeof(i); }; // expected-warning{{lambda capture 'i' is not required to be captured for this use}} expected-note {{substituting into a lambda}} + auto explicit_by_value_unused_decltype = [i] { decltype(i) j = 0; }; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}} + auto explicit_by_value_unused_const = [k] { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}} expected-note {{substituting into a lambda}} + auto explicit_by_value_unused_const_generic = [k](auto c) { return k + 1; }; // expected-warning{{lambda capture 'k' is not required to be captured for this use}} expected-note {{substituting into a lambda}} auto explicit_by_reference_used = [&i] { i++; }; - auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}} + auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}} auto explicit_initialized_reference_used = [&j = i] { return j + 1; }; - auto explicit_initialized_reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}} + auto explicit_initialized_reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}} auto explicit_initialized_value_used = [j = 1] { return j + 1; }; - auto explicit_initialized_value_unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}} + auto explicit_initialized_value_unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}} auto explicit_initialized_value_non_trivial_constructor = [j = NonTrivialConstructor()]{}; auto explicit_initialized_value_non_trivial_destructor = [j = NonTrivialDestructor()]{}; - auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}} + auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}} expected-note {{substituting into a lambda}} auto explicit_initialized_value_non_trivial_init = [j = Trivial(42)]{}; auto explicit_initialized_value_with_side_effect = [j = side_effect()]{}; auto explicit_initialized_value_generic_used = [i = 1](auto c) mutable { i++; }; - auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}} + auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}} - auto nested = [&i] { + auto nested = [&i] { // expected-note {{substituting into a lambda}} auto explicit_by_value_used = [i] { return i + 1; }; - auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} + auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}} }; Trivial trivial; - auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}} + auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}} expected-note {{substituting into a lambda}} NonTrivialConstructor cons; - auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}} + auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}} expected-note {{substituting into a lambda}} NonTrivialCopyConstructor copy_cons; auto explicit_by_value_non_trivial_copy_constructor = [copy_cons] {}; @@ -189,7 +189,7 @@ void test_templated() { } void test_use_template() { - test_templated(); // expected-note{{in instantiation of function template specialization 'test_templated' requested here}} + test_templated(); // expected-note 13{{in instantiation of function template specialization 'test_templated' requested here}} } namespace pr35555 { diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index d28c2b22bd045..d348e7a7efaf9 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -119,7 +119,7 @@ namespace PackInTypeConstraint { []() -> C auto{ return T(); }(); // expected-error {{expression contains unexpanded parameter pack 'T'}} } template void g5() { - ([]() -> C auto{ // expected-error-re {{deduced type {{.*}} does not satisfy}} + ([]() -> C auto{ // expected-error-re {{deduced type {{.*}} does not satisfy}} expected-note {{while substituting into a lambda}} return T(); }(), ...); } diff --git a/clang/test/SemaTemplate/cxx1z-using-declaration.cpp b/clang/test/SemaTemplate/cxx1z-using-declaration.cpp index 84e3bff159822..a1f1988efd608 100644 --- a/clang/test/SemaTemplate/cxx1z-using-declaration.cpp +++ b/clang/test/SemaTemplate/cxx1z-using-declaration.cpp @@ -157,7 +157,7 @@ template void fn2() { // Test partial substitution into class-scope pack. template auto lambda1() { - return [](auto x) { + return [](auto x) { // expected-note 1+{{substituting into a lambda}} struct A : T::template X... { // expected-note 1+{{instantiation of}} using T::template X::f ...; using typename T::template X::type ...; diff --git a/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp b/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp index c5290efafc1ab..d66e68dc9e9c8 100644 --- a/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp +++ b/clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp @@ -160,7 +160,7 @@ namespace Variadic { consume([]() noexcept(sizeof(T) == 4) {} ...); } template void j() { - consume([](void (*p)() noexcept(B)) { + consume([](void (*p)() noexcept(B)) { // expected-note {{substituting into a lambda}} void (*q)() noexcept = p; // expected-error {{not superset of source}} } ...); } diff --git a/clang/test/SemaTemplate/instantiate-local-class.cpp b/clang/test/SemaTemplate/instantiate-local-class.cpp index f0f3d2b146b67..430516aaac5b5 100644 --- a/clang/test/SemaTemplate/instantiate-local-class.cpp +++ b/clang/test/SemaTemplate/instantiate-local-class.cpp @@ -473,7 +473,8 @@ namespace rdar23721638 { template void bar() { auto lambda = [](T a = "") {}; // expected-error {{conversion function from 'const char[1]' to 'rdar23721638::A' invokes a deleted function}} \ // expected-note {{in instantiation of default function argument expression for 'operator()' required here}} \ - // expected-note {{passing argument to parameter 'a' here}} + // expected-note {{passing argument to parameter 'a' here}} \ + // expected-note {{while substituting into a lambda}} lambda(); } template void bar(); // expected-note {{in instantiation}} @@ -496,6 +497,7 @@ namespace PR45000 { // expected-error@-1 {{cannot initialize a parameter of type 'int' with an rvalue of type 'std::nullptr_t'}} // expected-note@-2 {{in instantiation of default function argument expression for 'operator()' required here}} // expected-note@-3 {{passing argument to parameter 'x' here}} + // expected-note@-4 {{while substituting into a lambda}} void g() { f(); } // expected-note@-1 {{in instantiation of default function argument expression for 'f' required here}} diff --git a/clang/www/cxx_status.html b/clang/www/cxx_status.html index e4ecb5f832e93..e43159aabaeba 100755 --- a/clang/www/cxx_status.html +++ b/clang/www/cxx_status.html @@ -1024,11 +1024,7 @@

C++20 implementation status

Lambdas in unevaluated contexts
P0315R4 - -
Partial - temp.deduct/9 is not implemented yet. -
- + Clang 17