Commit 8ca33347 by Jakub Jelinek Committed by Jakub Jelinek

Implement P0018R3, C++17 lambda capture of *this by value as [=,*this]

	Implement P0018R3, C++17 lambda capture of *this by value as [=,*this]
	* parser.c (cp_parser_lambda_introducer): Formatting fix.  Pass
	true instead of false as by_reference_p to add_capture for 'this'.
	Parse '*this' simple-capture.
	* lambda.c (build_capture_proxy): Handle '*this' capture by value.
	(add_capture): Adjust function comment.  For id == this_identifier,
	treat by_reference_p as capturing '*this' by reference, i.e. 'this'
	by value, and !by_reference_p as capturing '*this' by value.
	(add_default_capture): For implicit 'this' capture, always pass
	by_reference_p true rather than false.

	* g++.dg/cpp1z/lambda-this1.C: New test.
	* g++.dg/cpp1z/lambda-this2.C: New test.

From-SVN: r240556
parent 459bcfb0
2016-09-27 Jakub Jelinek <jakub@redhat.com>
Implement P0018R3, C++17 lambda capture of *this by value as [=,*this]
* parser.c (cp_parser_lambda_introducer): Formatting fix. Pass
true instead of false as by_reference_p to add_capture for 'this'.
Parse '*this' simple-capture.
* lambda.c (build_capture_proxy): Handle '*this' capture by value.
(add_capture): Adjust function comment. For id == this_identifier,
treat by_reference_p as capturing '*this' by reference, i.e. 'this'
by value, and !by_reference_p as capturing '*this' by value.
(add_default_capture): For implicit 'this' capture, always pass
by_reference_p true rather than false.
PR c++/77722
* cp-gimplify.c (cp_ubsan_maybe_instrument_return): Instrument also
functions that have just a STATEMENT_LIST instead of BIND_EXPR, or
......
......@@ -380,6 +380,13 @@ build_capture_proxy (tree member)
type = lambda_proxy_type (object);
if (name == this_identifier && !POINTER_TYPE_P (type))
{
type = build_pointer_type (type);
type = cp_build_qualified_type (type, TYPE_QUAL_CONST);
object = build_fold_addr_expr_with_type (object, type);
}
if (DECL_VLA_CAPTURE_P (member))
{
/* Rebuild the VLA type from the pointer and maxindex. */
......@@ -440,7 +447,8 @@ vla_capture_type (tree array_type)
/* From an ID and INITIALIZER, create a capture (by reference if
BY_REFERENCE_P is true), add it to the capture-list for LAMBDA,
and return it. */
and return it. If ID is `this', BY_REFERENCE_P says whether
`*this' is captured by reference. */
tree
add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
......@@ -499,7 +507,14 @@ add_capture (tree lambda, tree id, tree orig_init, bool by_reference_p,
type = lambda_capture_field_type (initializer, explicit_init_p);
if (type == error_mark_node)
return error_mark_node;
if (by_reference_p)
if (id == this_identifier && !by_reference_p)
{
gcc_assert (POINTER_TYPE_P (type));
type = TREE_TYPE (type);
initializer = cp_build_indirect_ref (initializer, RO_NULL,
tf_warning_or_error);
}
if (id != this_identifier && by_reference_p)
{
type = build_reference_type (type);
if (!dependent_type_p (type) && !lvalue_p (initializer))
......@@ -628,8 +643,8 @@ add_default_capture (tree lambda_stack, tree id, tree initializer)
id,
initializer,
/*by_reference_p=*/
(!this_capture_p
&& (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
(this_capture_p
|| (LAMBDA_EXPR_DEFAULT_CAPTURE_MODE (lambda)
== CPLD_REFERENCE)),
/*explicit_init_p=*/false);
initializer = convert_from_reference (var);
......
......@@ -9899,7 +9899,25 @@ cp_parser_lambda_introducer (cp_parser* parser, tree lambda_expr)
cp_lexer_consume_token (parser->lexer);
add_capture (lambda_expr,
/*id=*/this_identifier,
/*initializer=*/finish_this_expr(),
/*initializer=*/finish_this_expr (),
/*by_reference_p=*/true,
explicit_init_p);
continue;
}
/* Possibly capture `*this'. */
if (cp_lexer_next_token_is (parser->lexer, CPP_MULT)
&& cp_lexer_nth_token_is_keyword (parser->lexer, 2, RID_THIS))
{
location_t loc = cp_lexer_peek_token (parser->lexer)->location;
if (cxx_dialect < cxx1z)
pedwarn (loc, 0, "%<*this%> capture only available with "
"-std=c++1z or -std=gnu++1z");
cp_lexer_consume_token (parser->lexer);
cp_lexer_consume_token (parser->lexer);
add_capture (lambda_expr,
/*id=*/this_identifier,
/*initializer=*/finish_this_expr (),
/*by_reference_p=*/false,
explicit_init_p);
continue;
2016-09-27 Jakub Jelinek <jakub@redhat.com>
* g++.dg/cpp1z/lambda-this1.C: New test.
* g++.dg/cpp1z/lambda-this2.C: New test.
PR c++/77722
* g++.dg/ubsan/return-4.C: New test.
* g++.dg/ubsan/return-5.C: New test.
......
// P0018R3 - C++17 lambda capture of *this
// { dg-do compile { target c++11 } }
struct A {
int a;
void foo () {
int v = 4;
auto b = [*this, this] {}; // { dg-error "already captured 'this'" }
// { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
auto c = [this, *this] {}; // { dg-error "already captured 'this'" }
// { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
auto d = [this] { return a; };
auto e = [*this] { return a; }; // { dg-error "'*this' capture only available with" "" { target c++14_down } }
auto f = [this] { a++; };
auto g = [*this] { a++; }; // { dg-error "in read-only object" }
// { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
auto h = [*this] () mutable { a++; };// { dg-error "'*this' capture only available with" "" { target c++14_down } }
auto i = [=] { return a; };
auto j = [&] { return a; };
auto k = [=, this] { return a; };// { dg-error "explicit by-copy capture of 'this' redundant with by-copy capture default" }
auto l = [&, this] { return a; };
auto m = [=, *this] { return a; };// { dg-error "'*this' capture only available with" "" { target c++14_down } }
auto n = [&, *this] { return a; };// { dg-error "'*this' capture only available with" "" { target c++14_down } }
auto o = [*this, &v] { return a + v; };// { dg-error "'*this' capture only available with" "" { target c++14_down } }
auto p = [*this] { this = 0; }; // { dg-error "lvalue required as left operand of assignment" }
// { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
}
};
struct B {
double b;
B () : b (.007) {}
double foo () {
return [this]{ return [*this] { return b; }; }()(); // { dg-error "'*this' capture only available with" "" { target c++14_down } }
}
double bar () {
auto c = []{ return [*this] { return b; }; }; // { dg-error "'this' was not captured for this lambda function" }
} // { dg-error "invalid use of non-static data member 'B::b'" "" { target *-*-* } .-1 }
}; // { dg-error "'*this' capture only available with" "" { target c++14_down } .-2 }
struct C {
int c;
C (const C &) = delete;
void bar () const;
void foo () {
auto d = [this] { return c; };
auto e = [*this] { return c; }; // { dg-error "use of deleted function" }
// { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
auto f = [=] { return c; };
auto g = [&] { return c; };
auto h = [this] { bar (); };
auto i = [*this] { bar (); }; // { dg-error "use of deleted function" }
// { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
}
};
struct D {
int d;
~D () = delete;
void bar () const;
void foo () {
auto e = [this] { return d; };
auto f = [*this] { return d; }; // { dg-error "use of deleted function" }
// { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
auto g = [=] { return d; };
auto h = [&] { return d; };
auto i = [this] { bar (); };
auto j = [*this] { bar (); }; // { dg-error "use of deleted function" }
// { dg-error "'*this' capture only available with" "" { target c++14_down } .-1 }
}
};
// P0018R3 - C++17 lambda capture of *this
// { dg-do run { target c++11 } }
// { dg-options "" }
extern "C" void abort ();
struct A {
int a, z;
A () : a (4), z (0) {}
A (const A &x) : a (x.a), z (1) {}
void foo () {
if (z != 0) abort ();
auto b = [this] { return &a; };
auto c = [*this] { return &a; }; // { dg-warning "'*this' capture only available with" "" { target c++14_down } }
auto d = [=] { return &a; };
auto e = [&] { return &a; };
if (b () != &a) abort ();
if (*b () != 4) abort ();
auto f = c ();
if (c () == &a) abort ();
if (c () != f) abort ();
if (*c () != 4) abort ();
if (d () != &a) abort ();
if (e () != &a) abort ();
auto g = [this] { return a + z; };
auto h = [*this] { return a + z; }; // { dg-warning "'*this' capture only available with" "" { target c++14_down } }
auto i = [=] { return a + z; };
auto j = [&] { return a + z; };
if (g () != 4 || h () != 5 || i () != 4 || j () != 4) abort ();
}
};
template <int N>
struct B {
int a, z;
B () : a (N), z (0) {}
B (const B &x) : a (x.a), z (1) {}
void foo () {
if (z != 0) abort ();
auto b = [this] { return &a; };
auto c = [*this] { return &a; }; // { dg-warning "'*this' capture only available with" "" { target c++14_down } }
auto d = [=] { return &a; };
auto e = [&] { return &a; };
if (b () != &a) abort ();
if (*b () != 9) abort ();
auto f = c ();
if (c () == &a) abort ();
if (c () != f) abort ();
if (*c () != 9) abort ();
if (d () != &a) abort ();
if (e () != &a) abort ();
auto g = [this] { return a + z; };
auto h = [*this] { return a + z; }; // { dg-warning "'*this' capture only available with" "" { target c++14_down } }
auto i = [=] { return a + z; };
auto j = [&] { return a + z; };
if (g () != 9 || h () != 10 || i () != 9 || j () != 9) abort ();
}
};
int
main ()
{
A a;
a.foo ();
B<9> b;
b.foo ();
return 0;
}
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment