c++: Fix DMI with lambda 'this' capture [PR94205]
authorJason Merrill <jason@redhat.com>
Tue, 31 Mar 2020 21:34:47 +0000 (17:34 -0400)
committerJason Merrill <jason@redhat.com>
Wed, 1 Apr 2020 05:17:23 +0000 (01:17 -0400)
We represent 'this' in a default member initializer with a PLACEHOLDER_EXPR.
Normally in constexpr evaluation when we encounter one it refers to
ctx->ctor, but when we're creating a temporary of class type, that replaces
ctx->ctor, so a PLACEHOLDER_EXPR that refers to the type of the member being
initialized needs to be replaced before that happens.

gcc/cp/ChangeLog
2020-03-31  Jason Merrill  <jason@redhat.com>

PR c++/94205
* constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Call
replace_placeholders.
* typeck2.c (store_init_value): Fix arguments to
fold_non_dependent_expr.

gcc/cp/ChangeLog
gcc/cp/constexpr.c
gcc/cp/tree.c
gcc/cp/typeck2.c
gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi2.C [new file with mode: 0644]
gcc/testsuite/g++.dg/cpp1z/lambda-this4.C [new file with mode: 0644]

index 2814a866f5d54a95cdd536d98e8429b7debc4e92..3b522e8278c2a3e60de63eafa13048c2889a5f7e 100644 (file)
@@ -1,3 +1,11 @@
+2020-03-31  Jason Merrill  <jason@redhat.com>
+
+       PR c++/94205
+       * constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Call
+       replace_placeholders.
+       * typeck2.c (store_init_value): Fix arguments to
+       fold_non_dependent_expr.
+
 2020-03-31  Jason Merrill  <jason@redhat.com>
 
        * constexpr.c (cxx_eval_constant_expression) [TARGET_EXPR]: Use
index e85b3c113f06dcb2b26c9d39a1e750893ced7fbc..91f0c3ba269ec1d1ee4600e2152f06143fac1f8e 100644 (file)
@@ -5553,6 +5553,12 @@ cxx_eval_constant_expression (const constexpr_ctx *ctx, tree t,
        tree init = TARGET_EXPR_INITIAL (t);
        if ((AGGREGATE_TYPE_P (type) || VECTOR_TYPE_P (type)))
          {
+           if (ctx->object)
+             /* If the initializer contains any PLACEHOLDER_EXPR, we need to
+                resolve them before we create a new CONSTRUCTOR for the
+                temporary.  */
+             init = replace_placeholders (init, ctx->object);
+
            /* We're being expanded without an explicit target, so start
               initializing a new object; expansion with an explicit target
               strips the TARGET_EXPR before we get here.  */
index a2172dea0d8a9af0b67d2b6ad17ef4f244953871..5eb0dcd717addb77612a893a482860b3d2347495 100644 (file)
@@ -3239,7 +3239,7 @@ replace_placeholders_r (tree* t, int* walk_subtrees, void* data_)
    a PLACEHOLDER_EXPR has been encountered.  */
 
 tree
-replace_placeholders (tree exp, tree obj, bool *seen_p)
+replace_placeholders (tree exp, tree obj, bool *seen_p /*= NULL*/)
 {
   /* This is only relevant for C++14.  */
   if (cxx_dialect < cxx14)
index bff4ddbcf81de7930fd300055541186fc85a1c38..cf1cb5ace665be84c55ffdc8645de16484994824 100644 (file)
@@ -871,7 +871,7 @@ store_init_value (tree decl, tree init, vec<tree, va_gc>** cleanups, int flags)
     {
       bool const_init;
       tree oldval = value;
-      value = fold_non_dependent_expr (value);
+      value = fold_non_dependent_expr (value, tf_warning_or_error, true, decl);
       if (DECL_DECLARED_CONSTEXPR_P (decl)
          || (DECL_IN_AGGR_P (decl)
              && DECL_INITIALIZED_IN_CLASS_P (decl)))
diff --git a/gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi2.C b/gcc/testsuite/g++.dg/cpp1y/constexpr-nsdmi2.C
new file mode 100644 (file)
index 0000000..c51f734
--- /dev/null
@@ -0,0 +1,20 @@
+// PR c++/94205
+// { dg-do compile { target c++14 } }
+
+struct S
+{
+  struct A
+  {
+    S *p;
+    constexpr A(S* p): p(p) {}
+    constexpr operator int() { p->i = 5; return 6; }
+  };
+  int i;
+  int a = A(this);
+};
+
+
+constexpr S s = {};
+
+#define SA(X) static_assert((X),#X)
+SA(s.i == 5 && s.a == 6);
diff --git a/gcc/testsuite/g++.dg/cpp1z/lambda-this4.C b/gcc/testsuite/g++.dg/cpp1z/lambda-this4.C
new file mode 100644 (file)
index 0000000..5d96879
--- /dev/null
@@ -0,0 +1,13 @@
+// PR c++/94205
+// { dg-do compile { target c++17 } }
+
+struct S
+{
+  int i;
+  int a = [this] { this->i = 5; return 6; } ();
+};
+
+
+constexpr S s = {};
+
+static_assert (s.i == 5 && s.a == 6);