Skip to content

Commit

Permalink
[clang] Correctly implement CWG 2672 (#75001)
Browse files Browse the repository at this point in the history
  • Loading branch information
zyn0217 committed Jan 5, 2024
1 parent 7648371 commit 3eeed79
Show file tree
Hide file tree
Showing 16 changed files with 39 additions and 54 deletions.
3 changes: 2 additions & 1 deletion clang/docs/ReleaseNotes.rst
Original file line number Diff line number Diff line change
Expand Up @@ -723,7 +723,8 @@ Bug Fixes to C++ Support

- 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>`_).
(`#64138 <https://github.com/llvm/llvm-project/issues/64138>`_) and
(`#71684 <https://github.com/llvm/llvm-project/issues/71684>`_).

- Update ``FunctionDeclBitfields.NumFunctionDeclBits``. This fixes:
(`#64171 <https://github.com/llvm/llvm-project/issues/64171>`_).
Expand Down
11 changes: 1 addition & 10 deletions clang/lib/Sema/SemaTemplateInstantiate.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@
#include "clang/Sema/Template.h"
#include "clang/Sema/TemplateDeduction.h"
#include "clang/Sema/TemplateInstCallback.h"
#include "llvm/ADT/ScopeExit.h"
#include "llvm/ADT/StringExtras.h"
#include "llvm/Support/ErrorHandling.h"
#include "llvm/Support/TimeProfiler.h"
Expand Down Expand Up @@ -1142,8 +1141,7 @@ std::optional<TemplateDeductionInfo *> Sema::isSFINAEContext() const {
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.
[[fallthrough]];
// body, see [temp.deduct]p9.
case CodeSynthesisContext::ConstraintSubstitution:
case CodeSynthesisContext::RequirementInstantiation:
case CodeSynthesisContext::RequirementParameterInstantiation:
Expand Down Expand Up @@ -1445,13 +1443,6 @@ namespace {
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;
Expand Down
7 changes: 7 additions & 0 deletions clang/lib/Sema/TreeTransform.h
Original file line number Diff line number Diff line change
Expand Up @@ -13685,10 +13685,17 @@ TreeTransform<Derived>::TransformLambdaExpr(LambdaExpr *E) {
getSema().PushExpressionEvaluationContext(
Sema::ExpressionEvaluationContext::PotentiallyEvaluated);

Sema::CodeSynthesisContext C;
C.Kind = clang::Sema::CodeSynthesisContext::LambdaExpressionSubstitution;
C.PointOfInstantiation = E->getBody()->getBeginLoc();
getSema().pushCodeSynthesisContext(C);

// Instantiate the body of the lambda expression.
StmtResult Body =
Invalid ? StmtError() : getDerived().TransformLambdaBody(E, E->getBody());

getSema().popCodeSynthesisContext();

// ActOnLambda* will pop the function scope for us.
FuncScopeCleanup.disable();

Expand Down
2 changes: 1 addition & 1 deletion clang/test/CXX/drs/dr26xx.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -211,7 +211,7 @@ void f(...);

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

Expand Down
Original file line number Diff line number Diff line change
Expand Up @@ -35,8 +35,7 @@ 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 {{while substituting into a lambda expression here}}
// expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}}
l1(t);
}

Expand All @@ -46,8 +45,7 @@ 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 {{while substituting into a lambda expression here}}
// expected-note {{in instantiation of default function argument expression for 'operator()<NoDefaultCtor>' required here}}
l1();
}

Expand Down
2 changes: 0 additions & 2 deletions clang/test/CXX/expr/expr.prim/expr.prim.lambda/p11-1y.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -35,7 +35,6 @@ 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@-1 {{while substituting into a lambda expression here}}
}
template void init_kind_template<int>();
template void init_kind_template<ExplicitCopy>(); // expected-note {{instantiation of}}
Expand All @@ -53,7 +52,6 @@ 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@-1 {{while substituting into a lambda expression here}}
template void pack_1<>(); // expected-note {{instantiation of}}

// No lifetime-extension of the temporary here.
Expand Down
1 change: 0 additions & 1 deletion clang/test/CXX/expr/expr.prim/expr.prim.lambda/p23.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -85,7 +85,6 @@ 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@-1 2{{while substituting into a lambda expression}}
}
template void init_capture_pack_multi(); // expected-note {{instantiation}}
template void init_capture_pack_multi(int);
Expand Down
3 changes: 1 addition & 2 deletions clang/test/CXX/expr/expr.prim/expr.prim.lambda/p4.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -55,12 +55,11 @@ void test_result_type(int N) { // expected-note {{declared here}}
template <typename T>
void test_result_type_tpl(int N) { // expected-note 2{{declared here}}
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]; // expected-warning 2{{variable length arrays in C++ are a Clang extension}} \
expected-note 2{{function parameter 'N' with unknown value cannot be used in a constant expression}}
auto l2 = []() -> vla {}; // expected-error{{function cannot return array type 'vla' (aka 'int[N]')}}
}

void test_result_type_call() {
test_result_type_tpl<Incomplete>(10); // expected-note 2{{requested here}}
test_result_type_tpl<Incomplete>(10); // expected-note {{requested here}}
}
8 changes: 2 additions & 6 deletions clang/test/CXX/temp/temp.deduct/p9.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -28,18 +28,14 @@ template <class T>
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}}
h(0);
}

template <class T>
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}}
i(0);
}


Expand Down
8 changes: 4 additions & 4 deletions clang/test/SemaCXX/cxx1y-init-captures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -21,17 +21,17 @@ namespace variadic_expansion {
return a;
}() ...);
};
auto N2 = [x = y, //expected-note3{{begins here}} expected-note 6 {{default capture by}} expected-note 2 {{substituting into a lambda}}
auto N2 = [x = y, //expected-note3{{begins here}} expected-note 6 {{default capture by}}
&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}} expected-note 2{{substituting into a lambda}}
o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) { // expected-note 6 {{capture 't' by}} expected-note {{substituting into a lambda}}
fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}}
return a;
}() ...);
};

}

void h(int i, char c) { g(i, c); } //expected-note 2{{in instantiation}}
void h(int i, char c) { g(i, c); } // expected-note {{requested here}}
}

namespace odr_use_within_init_capture {
Expand Down
4 changes: 2 additions & 2 deletions clang/test/SemaCXX/cxx1z-lambda-star-this.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}} expected-note {{while substituting into a lambda}}
(void)[*this] { return x; }; //expected-error2{{call to deleted}}
}

B() = default;
Expand All @@ -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}} expected-note {{while substituting into a lambda}}
const auto &L = [*this](auto a) mutable { //expected-error{{call to deleted}}
d += a;
return [this](auto b) { return d += b; };
};
Expand Down
4 changes: 2 additions & 2 deletions clang/test/SemaCXX/lambda-expressions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -393,7 +393,7 @@ struct S {
namespace PR18473 {
template<typename T> void f() {
T t(0);
(void) [=]{ int n = t; }; // expected-error {{deleted}} expected-note {{while substituting into a lambda}}
(void) [=]{ int n = t; }; // expected-error {{deleted}}
}

template void f<int>();
Expand Down Expand Up @@ -476,7 +476,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) {}; // expected-note 2 {{while substituting into a lambda}}
auto x = [](typename T::ns::type &k) {};
}
class S {};
void foo() {
Expand Down
1 change: 0 additions & 1 deletion clang/test/SemaCXX/lambda-pack-expansion.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ 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) {
Expand Down
1 change: 0 additions & 1 deletion clang/test/SemaCXX/vartemplate-lambda.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -8,7 +8,6 @@ template<typename T> 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()<int *>' required here}}
// expected-note@-3{{passing argument to parameter 'a' here}}
// expected-note@-4{{substituting into a lambda}}

struct S {
template<class T>
Expand Down
28 changes: 14 additions & 14 deletions clang/test/SemaCXX/warn-unused-lambda-capture.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -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}} 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_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_reference_used = [&i] { i++; };
auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}} expected-note {{substituting into a lambda}}
auto explicit_by_reference_unused = [&i] {}; // expected-warning{{lambda capture 'i' is not used}}

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}} expected-note {{substituting into a lambda}}
auto explicit_initialized_reference_unused = [&j = i]{}; // expected-warning{{lambda capture 'j' is not used}}

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}} expected-note {{substituting into a lambda}}
auto explicit_initialized_value_unused = [j = 1] {}; // expected-warning{{lambda capture 'j' is not used}}
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}} expected-note {{substituting into a lambda}}
auto explicit_initialized_value_trivial_init = [j = Trivial()]{}; // expected-warning{{lambda capture 'j' is not used}}
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}} expected-note {{substituting into a lambda}}
auto explicit_initialized_value_generic_unused = [i = 1](auto c) mutable {}; // expected-warning{{lambda capture 'i' is not used}}

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}} expected-note {{substituting into a lambda}}
auto explicit_by_value_unused = [i] {}; // expected-warning{{lambda capture 'i' is not used}}
};

Trivial trivial;
auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}} expected-note {{substituting into a lambda}}
auto explicit_by_value_trivial = [trivial] {}; // expected-warning{{lambda capture 'trivial' is not used}}

NonTrivialConstructor cons;
auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}} expected-note {{substituting into a lambda}}
auto explicit_by_value_non_trivial_constructor = [cons] {}; // expected-warning{{lambda capture 'cons' is not used}}

NonTrivialCopyConstructor copy_cons;
auto explicit_by_value_non_trivial_copy_constructor = [copy_cons] {};
Expand All @@ -189,7 +189,7 @@ void test_templated() {
}

void test_use_template() {
test_templated<int>(); // expected-note 13{{in instantiation of function template specialization 'test_templated<int>' requested here}}
test_templated<int>(); // expected-note 3 {{requested here}}
}

namespace pr35555 {
Expand Down
4 changes: 1 addition & 3 deletions clang/test/SemaTemplate/instantiate-local-class.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -473,8 +473,7 @@ 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 {{while substituting into a lambda}}
// expected-note {{passing argument to parameter 'a' here}}
lambda();
}
template void bar<A>(); // expected-note {{in instantiation}}
Expand All @@ -497,7 +496,6 @@ 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()<int>' required here}}
// expected-note@-3 {{passing argument to parameter 'x' here}}
// expected-note@-4 {{while substituting into a lambda}}

void g() { f<int>(); }
// expected-note@-1 {{in instantiation of default function argument expression for 'f<int>' required here}}
Expand Down

0 comments on commit 3eeed79

Please sign in to comment.