+2020-04-14 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/94034
+ * constexpr.c (replace_result_decl_data): New struct.
+ (replace_result_decl_data_r): New function.
+ (replace_result_decl): New function.
+ (cxx_eval_call_expression): Use it.
+ * tree.c (build_aggr_init_expr): Set the location of the AGGR_INIT_EXPR
+ to that of its initializer.
+
2020-04-13 Marek Polacek <polacek@redhat.com>
PR c++/94588
return cp_build_addr_expr (obj, complain);
}
+/* Data structure used by replace_result_decl and replace_result_decl_r. */
+
+struct replace_result_decl_data
+{
+ /* The RESULT_DECL we want to replace. */
+ tree decl;
+ /* The replacement for DECL. */
+ tree replacement;
+ /* Whether we've performed any replacements. */
+ bool changed;
+};
+
+/* Helper function for replace_result_decl, called through cp_walk_tree. */
+
+static tree
+replace_result_decl_r (tree *tp, int *walk_subtrees, void *data)
+{
+ replace_result_decl_data *d = (replace_result_decl_data *) data;
+
+ if (*tp == d->decl)
+ {
+ *tp = unshare_expr (d->replacement);
+ d->changed = true;
+ *walk_subtrees = 0;
+ }
+ else if (TYPE_P (*tp))
+ *walk_subtrees = 0;
+
+ return NULL_TREE;
+}
+
+/* Replace every occurrence of DECL, a RESULT_DECL, with (an unshared copy of)
+ REPLACEMENT within the reduced constant expression *TP. Returns true iff a
+ replacement was performed. */
+
+static bool
+replace_result_decl (tree *tp, tree decl, tree replacement)
+{
+ gcc_checking_assert (TREE_CODE (decl) == RESULT_DECL
+ && (same_type_ignoring_top_level_qualifiers_p
+ (TREE_TYPE (decl), TREE_TYPE (replacement))));
+ replace_result_decl_data data = { decl, replacement, false };
+ cp_walk_tree_without_duplicates (tp, replace_result_decl_r, &data);
+ return data.changed;
+}
+
/* Subroutine of cxx_eval_constant_expression.
Evaluate the call expression tree T in the context of OLD_CALL expression
evaluation. */
break;
}
}
+
+ /* Rewrite all occurrences of the function's RESULT_DECL with the
+ current object under construction. */
+ if (!*non_constant_p && ctx->object
+ && AGGREGATE_TYPE_P (TREE_TYPE (res))
+ && !is_empty_class (TREE_TYPE (res)))
+ if (replace_result_decl (&result, res, ctx->object))
+ cacheable = false;
}
else
/* Couldn't get a function copy to evaluate. */
else
rval = init;
+ if (location_t loc = EXPR_LOCATION (init))
+ SET_EXPR_LOCATION (rval, loc);
+
return rval;
}
+2020-04-14 Patrick Palka <ppalka@redhat.com>
+
+ PR c++/94034
+ * g++.dg/cpp0x/constexpr-empty15.C: New test.
+ * g++.dg/cpp1y/constexpr-nsdmi6a.C: New test.
+ * g++.dg/cpp1y/constexpr-nsdmi6b.C: New test.
+ * g++.dg/cpp1y/constexpr-nsdmi7a.C: New test.
+ * g++.dg/cpp1y/constexpr-nsdmi7b.C: New test.
+
2020-04-14 Jakub Jelinek <jakub@redhat.com>
PR tree-optimization/94573
--- /dev/null
+// { dg-do compile { target c++11 } }
+
+struct empty1 { };
+constexpr empty1 foo1() { return {}; }
+
+struct empty2 { };
+constexpr empty2 foo2(empty1) { return {}; }
+
+constexpr empty2 a = foo2(foo1());
--- /dev/null
+// PR c++/94034
+// { dg-do compile { target c++14 } }
+
+struct A {
+ A *ap = this;
+};
+
+constexpr A foo()
+{
+ return {};
+}
+
+constexpr A bar()
+{
+ return foo();
+}
+
+void
+baz()
+{
+ constexpr A a = foo(); // { dg-error ".A..& a... is not a constant expression" }
+ constexpr A b = bar(); // { dg-error ".A..& b... is not a constant expression" }
+}
+
+constexpr A a = foo();
+constexpr A b = bar();
--- /dev/null
+// PR c++/94034
+// { dg-do compile { target c++14 } }
+
+struct A {
+ A() = default; A(const A&);
+ A *ap = this;
+};
+
+constexpr A foo()
+{
+ return {};
+}
+
+constexpr A bar()
+{
+ return foo();
+}
+
+void
+baz()
+{
+ constexpr A a = foo(); // { dg-error ".A..& a... is not a constant expression" }
+ constexpr A b = bar(); // { dg-error ".A..& b... is not a constant expression" }
+}
+
+constexpr A a = foo();
+constexpr A b = bar();
--- /dev/null
+// PR c++/94034
+// { dg-do compile { target c++14 } }
+
+struct A
+{
+ A *p = this;
+ int n = 2;
+ int m = p->n++;
+};
+
+constexpr A
+foo()
+{
+ return {};
+}
+
+constexpr A
+bar()
+{
+ A a = foo();
+ a.p->n = 5;
+ return a;
+}
+
+static_assert(bar().n == 5, "");
+
+constexpr int
+baz()
+{
+ A b = foo();
+ b.p->n = 10;
+ A c = foo();
+ if (c.p->n != 3 || c.p->m != 2)
+ __builtin_abort();
+ bar();
+ return 0;
+}
+
+static_assert(baz() == 0, "");
+
+constexpr int
+quux()
+{
+ const A d = foo();
+ d.p->n++; // { dg-error "const object" }
+ return 0;
+}
+
+static_assert(quux() == 0, ""); // { dg-error "non-constant" }
--- /dev/null
+// PR c++/94034
+// { dg-do compile { target c++14 } }
+
+struct A
+{
+ A() = default; A(const A&);
+ A *p = this;
+ int n = 2;
+ int m = p->n++;
+};
+
+constexpr A
+foo()
+{
+ return {};
+}
+
+constexpr A
+bar()
+{
+ A a = foo();
+ a.p->n = 5;
+ return a; // { dg-error "non-.constexpr." }
+}
+
+constexpr int
+baz()
+{
+ A b = foo();
+ b.p->n = 10;
+ A c = foo();
+ if (c.p->n != 3 || c.p->m != 2)
+ __builtin_abort();
+ foo();
+ return 0;
+}
+
+static_assert(baz() == 0, "");
+
+constexpr int
+quux()
+{
+ const A d = foo();
+ d.p->n++; // { dg-error "const object" }
+ return 0;
+}
+
+static_assert(quux() == 0, ""); // { dg-error "non-constant" }