Files
clang-p2996/clang/test/SemaCXX/cxx1y-init-captures.cpp
Richard Smith 42a22370f2 Revert r350917 "[Sema] If CheckPlaceholderExpr rewrites the initializer
of an auto"

This commit changed the initializer expression passed into
initialization (stripping off an enclosing pair of parentheses or
braces) and subtly changing the meaning of programs, typically by
inserting bogus calls to copy constructors.

See the added testcase in test/SemaCXX/cxx1y-init-captures.cpp for an
example of the breakage.

llvm-svn: 359066
2019-04-24 02:22:38 +00:00

232 lines
5.3 KiB
C++

// RUN: %clang_cc1 -std=c++1y %s -verify -emit-llvm-only
// RUN: %clang_cc1 -std=c++1z %s -verify -emit-llvm-only
namespace variadic_expansion {
int f(int &, char &) { return 0; }
template<class ... Ts> char fv(Ts ... ts) { return 0; }
// FIXME: why do we get 2 error messages
template <typename ... T> void g(T &... t) { //expected-note3{{declared here}}
f([&a(t)]()->decltype(auto) {
return a;
}() ...);
auto L = [x = f([&a(t)]()->decltype(auto) { return a; }()...)]() { return x; };
const int y = 10;
auto M = [x = y,
&z = y](T& ... t) { };
auto N = [x = y,
&z = y, n = f(t...),
o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...), t...](T& ... s) {
fv([&a(t)]()->decltype(auto) {
return a;
}() ...);
};
auto N2 = [x = y, //expected-note3{{begins here}}
&z = y, n = f(t...),
o = f([&a(t)](T& ... t)->decltype(auto) { return a; }(t...)...)](T& ... s) {
fv([&a(t)]()->decltype(auto) { //expected-error 3{{captured}}
return a;
}() ...);
};
}
void h(int i, char c) { g(i, c); } //expected-note{{in instantiation}}
}
namespace odr_use_within_init_capture {
int test() {
{ // no captures
const int x = 10;
auto L = [z = x + 2](int a) {
auto M = [y = x - 2](char b) {
return y;
};
return M;
};
}
{ // should not capture
const int x = 10;
auto L = [&z = x](int a) {
return a;;
};
}
{
const int x = 10;
auto L = [k = x](char a) { //expected-note {{declared}}
return [](int b) { //expected-note {{begins}}
return [j = k](int c) { //expected-error {{cannot be implicitly captured}}
return c;
};
};
};
}
{
const int x = 10;
auto L = [k = x](char a) {
return [=](int b) {
return [j = k](int c) {
return c;
};
};
};
}
{
const int x = 10;
auto L = [k = x](char a) {
return [k](int b) {
return [j = k](int c) {
return c;
};
};
};
}
return 0;
}
int run = test();
}
namespace odr_use_within_init_capture_template {
template<class T = int>
int test(T t = T{}) {
{ // no captures
const T x = 10;
auto L = [z = x](char a) {
auto M = [y = x](T b) {
return y;
};
return M;
};
}
{ // should not capture
const T x = 10;
auto L = [&z = x](T a) {
return a;;
};
}
{ // will need to capture x in outer lambda
const T x = 10; //expected-note {{declared}}
auto L = [z = x](char a) { //expected-note {{begins}}
auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}}
return y;
};
return M;
};
}
{ // will need to capture x in outer lambda
const T x = 10;
auto L = [=,z = x](char a) {
auto M = [&y = x](T b) {
return y;
};
return M;
};
}
{ // will need to capture x in outer lambda
const T x = 10;
auto L = [x, z = x](char a) {
auto M = [&y = x](T b) {
return y;
};
return M;
};
}
{ // will need to capture x in outer lambda
const int x = 10; //expected-note {{declared}}
auto L = [z = x](char a) { //expected-note {{begins}}
auto M = [&y = x](T b) { //expected-error {{cannot be implicitly captured}}
return y;
};
return M;
};
}
{
// no captures
const T x = 10;
auto L = [z =
[z = x, &y = x](char a) { return z + y; }('a')](char a)
{ return z; };
}
return 0;
}
int run = test(); //expected-note {{instantiation}}
}
namespace classification_of_captures_of_init_captures {
template <typename T>
void f() {
[a = 24] () mutable {
[&a] { a = 3; }();
}();
}
template <typename T>
void h() {
[a = 24] (auto param) mutable {
[&a] { a = 3; }();
}(42);
}
int run() {
f<int>();
h<int>();
}
}
namespace N3922 {
struct X { X(); explicit X(const X&); int n; };
auto a = [x{X()}] { return x.n; }; // ok
auto b = [x = {X()}] {}; // expected-error{{<initializer_list>}}
}
namespace init_capture_non_mutable {
void test(double weight) {
double init;
auto find = [max = init](auto current) {
max = current; // expected-error{{cannot assign to a variable captured by copy in a non-mutable lambda}}
};
find(weight); // expected-note {{in instantiation of function template specialization}}
}
}
namespace init_capture_undeclared_identifier {
auto a = [x = y]{}; // expected-error{{use of undeclared identifier 'y'}}
int typo_foo; // expected-note 2 {{'typo_foo' declared here}}
auto b = [x = typo_boo]{}; // expected-error{{use of undeclared identifier 'typo_boo'; did you mean 'typo_foo'}}
auto c = [x(typo_boo)]{}; // expected-error{{use of undeclared identifier 'typo_boo'; did you mean 'typo_foo'}}
}
namespace copy_evasion {
struct A {
A();
A(const A&) = delete;
};
auto x = [a{A()}] {};
#if __cplusplus >= 201702L
// ok, does not copy an 'A'
#else
// expected-error@-4 {{call to deleted}}
// expected-note@-7 {{deleted}}
#endif
}