aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
-rw-r--r--gcc/cp/ChangeLog11
-rw-r--r--gcc/cp/lambda.c23
-rw-r--r--gcc/cp/parser.c20
-rw-r--r--gcc/testsuite/ChangeLog3
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/lambda-this1.C68
-rw-r--r--gcc/testsuite/g++.dg/cpp1z/lambda-this2.C68
6 files changed, 188 insertions, 5 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog
index 75c9d36..1a1f186 100644
--- a/gcc/cp/ChangeLog
+++ b/gcc/cp/ChangeLog
@@ -1,5 +1,16 @@
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
diff --git a/gcc/cp/lambda.c b/gcc/cp/lambda.c
index d511185..cd32226 100644
--- a/gcc/cp/lambda.c
+++ b/gcc/cp/lambda.c
@@ -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);
diff --git a/gcc/cp/parser.c b/gcc/cp/parser.c
index 5ec8b1b..f672b8d 100644
--- a/gcc/cp/parser.c
+++ b/gcc/cp/parser.c
@@ -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;
diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog
index 443a917..59e20b7 100644
--- a/gcc/testsuite/ChangeLog
+++ b/gcc/testsuite/ChangeLog
@@ -1,5 +1,8 @@
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.
diff --git a/gcc/testsuite/g++.dg/cpp1z/lambda-this1.C b/gcc/testsuite/g++.dg/cpp1z/lambda-this1.C
new file mode 100644
index 0000000..5a4c5f9
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/lambda-this1.C
@@ -0,0 +1,68 @@
+// 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 }
+ }
+};
diff --git a/gcc/testsuite/g++.dg/cpp1z/lambda-this2.C b/gcc/testsuite/g++.dg/cpp1z/lambda-this2.C
new file mode 100644
index 0000000..5a0066d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp1z/lambda-this2.C
@@ -0,0 +1,68 @@
+// 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;
+}