[clang] 629170f - [Sema] Lambdas are not part of immediate context for deduction
Ilya Biryukov via cfe-commits
cfe-commits at lists.llvm.org
Tue May 9 03:10:27 PDT 2023
Author: Ilya Biryukov
Date: 2023-05-09T12:06:33+02:00
New Revision: 629170fe452f4849c89fc289d6e2cf5f08534342
URL: https://github.com/llvm/llvm-project/commit/629170fe452f4849c89fc289d6e2cf5f08534342
DIFF: https://github.com/llvm/llvm-project/commit/629170fe452f4849c89fc289d6e2cf5f08534342.diff
LOG: [Sema] Lambdas are not part of immediate context for deduction
This commit implements [temp.deduct]p9.
Test updates include:
- New notes in `cxx1y-init-captures.cpp`, `lambda-expressions.cpp`
and 'warn-unused-lambda-capture.cpp'.
This seems to be caused by diagnosing errors earlier (during
deduction) that were previously surfaced later (during
instantiation).
- New error `lambda-unevaluated.cpp` is in line with [temp.deduct]p9.
Reviewed By: erichkeane, #clang-language-wg
Differential Revision: https://reviews.llvm.org/D148802
Added:
clang/test/CXX/temp/temp.deduct/p9.cpp
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/include/clang/Sema/Sema.h
clang/lib/Frontend/FrontendActions.cpp
clang/lib/Sema/SemaTemplateInstantiate.cpp
clang/test/CXX/expr/expr.prim/expr.prim.lambda/default-arguments.cpp
clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
clang/test/CXX/stmt.stmt/stmt.select/stmt.if/p2.cpp
clang/test/CXX/temp/temp.param/p15-cxx0x.cpp
clang/test/PCH/cxx1y-init-captures.cpp
clang/test/SemaCXX/cxx1y-generic-lambdas-capturing.cpp
clang/test/SemaCXX/cxx1y-generic-lambdas.cpp
clang/test/SemaCXX/cxx1y-init-captures.cpp
clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
clang/test/SemaCXX/cxx20-decomposition.cpp
clang/test/SemaCXX/lambda-expressions.cpp
clang/test/SemaCXX/lambda-pack-expansion.cpp
clang/test/SemaCXX/lambda-unevaluated.cpp
clang/test/SemaCXX/vartemplate-lambda.cpp
clang/test/SemaCXX/warn-unused-lambda-capture.cpp
clang/test/SemaTemplate/concepts.cpp
clang/test/SemaTemplate/cxx1z-using-declaration.cpp
clang/test/SemaTemplate/instantiate-exception-spec-cxx11.cpp
clang/test/SemaTemplate/instantiate-local-class.cpp
clang/www/cxx_status.html
Removed:
################################################################################
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 <optional>
@@ -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<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();
@@ -1038,6 +1045,15 @@ std::optional<TemplateDeductionInfo *> 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<TemplateDeductionInfo *> 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<TemplateInstantiator> 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<typename T>
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()<NoDefaultCtor>' required here}}
+ // expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' 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<typename T>
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()<NoDefaultCtor>' required here}}
+ // expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' 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<typename T> void init_kind_template() {
auto init_kind_1 = [ec(T())] {};
auto init_kind_2 = [ec = T()] {}; // expected-error {{no matching constructor}}
+ // expected-note at -1 {{while substituting into a lambda expression here}}
}
template void init_kind_template<int>();
template void init_kind_template<ExplicitCopy>(); // 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<typename...T> void pack_1(T...t) { (void)[a(t...)] {}; } // expected-error {{initializer missing for lambda capture 'a'}}
+ // expected-note at -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<typename T> T instantiate_test(T t) {
[x(&t)]() { *x = 1; } (); // expected-error {{assigning to 'const char *'}}
+ // expected-note at -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<typename ...Args>
void init_capture_pack_multi(Args ...args) {
[as(args...)] {} (); // expected-error {{initializer missing for lambda capture 'as'}} expected-error {{multiple}}
+ // expected-note at -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 <typename T>
void test_result_type_tpl(int N) {
auto l1 = []() -> T {}; // expected-error{{incomplete result type 'Incomplete' in lambda expression}}
+ // expected-note at -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 at -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 at -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 <class T>
+auto f(T) -> decltype([]() { T::invalid; } ());
+void f(...);
+void test_f() {
+ f(0); // expected-error at -3 {{type 'int' cannot be used prior to '::'}}
+ // expected-note at -1 {{while substituting deduced template arguments}}
+ // expected-note at -5 {{while substituting into a lambda expression here}}
+}
+
+template <class T, unsigned = sizeof([]() { T::invalid; })>
+void g(T);
+void g(...);
+void test_g() {
+ g(0); // expected-error at -4 {{type 'int' cannot be used prior to '::'}}
+ // expected-note at -4 {{in instantiation of default argument}}
+ // expected-note at -2 {{while substituting deduced template arguments}}
+ // expected-note at -7 {{while substituting into a lambda expression here}}
+}
+
+template <class T>
+auto h(T) -> decltype([x = T::invalid]() { });
+void h(...);
+void test_h() {
+ h(0); // expected-error at -3 {{type 'int' cannot be used prior to '::'}}
+ // expected-note at -1 {{while substituting deduced template arguments}}
+ // expected-note at -5 {{while substituting into a lambda expression here}}
+}
+
+template <class T>
+auto i(T) -> decltype([]() -> typename T::invalid { });
+void i(...);
+void test_i() {
+ i(0); // expected-error at -3 {{type 'int' cannot be used prior to '::'}}
+ // expected-note at -1 {{while substituting deduced template arguments}}
+ // expected-note at -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 <class T>
+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<typename...Ts> struct A {
B() {
consume([]{
int arr[Vs]; // expected-error {{negative size}}
+ // expected-note at -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 at 18 {{lvalue of type 'const char *const'}}
+ // expected-note at 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 <class T = int>
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 <class T = int>
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<typename T> 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<int>();
@@ -466,7 +467,7 @@ namespace error_in_transform_prototype {
void f(T t) {
// expected-error at +2 {{type 'int' cannot be used prior to '::' because it has no members}}
// expected-error at +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 at -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 <class T>
auto g(T) -> decltype([]() { T::invalid; } ());
-auto e = g(0); // expected-error{{no matching function for call}}
-// expected-note at -2 {{substitution failure}}
+auto e = g(0); // expected-error at -1{{type 'int' cannot be used prior to '::'}}
+ // expected-note at -1{{while substituting deduced template}}
+ // expected-note at -3{{while substituting into a lambda}}
+ // expected-error at -3 {{no matching function for call to 'g'}}
+ // expected-note at -5 {{substitution failure}}
template <typename T>
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 <class T>
+concept lambda_works = requires {
+ []() { T::foo(); };
+};
+
+static_assert(!lambda_works<int>);
+static_assert(lambda_works<WithFoo>);
+
+template <class T>
+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 <class T>
+auto direct_lambda(T) -> decltype([] { T::foo(); }) {}
+void direct_lambda(...) {}
+
+void recursive() {
+ direct_lambda(0); // expected-error at -4 {{type 'int' cannot be used prior to '::'}}
+ // expected-note at -1 {{while substituting deduced template arguments}}
+ // expected-note at -6 {{while substituting into a lambda}}
+ bool x = requires { direct_lambda(0); }; // expected-error at -7 {{type 'int' cannot be used prior to '::'}}
+ // expected-note at -1 {{while substituting deduced template arguments}}
+ // expected-note at -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<typename T> auto v1 = [](int a = T()) { return a; }();
// expected-error at -1{{cannot initialize a parameter of type 'int' with an rvalue of type 'int *'}}
// expected-note at -2{{in instantiation of default function argument expression for 'operator()<int *>' required here}}
// expected-note at -3{{passing argument to parameter 'a' here}}
+// expected-note at -4{{substituting into a lambda}}
struct S {
template<class T>
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<int>(); // expected-note{{in instantiation of function template specialization 'test_templated<int>' requested here}}
+ test_templated<int>(); // expected-note 13{{in instantiation of function template specialization 'test_templated<int>' 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<T> auto{ return T(); }(); // expected-error {{expression contains unexpanded parameter pack 'T'}}
}
template<typename ...T> void g5() {
- ([]() -> C<T> auto{ // expected-error-re {{deduced type {{.*}} does not satisfy}}
+ ([]() -> C<T> 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<typename ...T> void fn2() {
// Test partial substitution into class-scope pack.
template<typename ...T> auto lambda1() {
- return [](auto x) {
+ return [](auto x) { // expected-note 1+{{substituting into a lambda}}
struct A : T::template X<decltype(x)>... { // expected-note 1+{{instantiation of}}
using T::template X<decltype(x)>::f ...;
using typename T::template X<decltype(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<bool ...B> 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 <typename T> 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()<rdar23721638::A>' 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<A>(); // expected-note {{in instantiation}}
@@ -496,6 +497,7 @@ namespace PR45000 {
// expected-error at -1 {{cannot initialize a parameter of type 'int' with an rvalue of type 'std::nullptr_t'}}
// expected-note at -2 {{in instantiation of default function argument expression for 'operator()<int>' required here}}
// expected-note at -3 {{passing argument to parameter 'x' here}}
+ // expected-note at -4 {{while substituting into a lambda}}
void g() { f<int>(); }
// expected-note at -1 {{in instantiation of default function argument expression for 'f<int>' 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 @@ <h2 id="cxx20">C++20 implementation status</h2>
<tr>
<td>Lambdas in unevaluated contexts</td>
<td><a href="https://wg21.link/p0315r4">P0315R4</a></td>
- <td class="partial" align="center">
- <details><summary>Partial</summary>
- temp.deduct/9 is not implemented yet.
- </details>
- </td>
+ <td class="full" align="center">Clang 17</td>
</tr>
<!-- Jacksonville papers -->
<tr>
More information about the cfe-commits
mailing list