Lewis reported another testcase which hits the "accessing uninitialized
member" error, and can lead to wrong values.
Tested x86_64-pc-linux-gnu, applying to trunk.
commit 1bfb2997968d18b337cbd144a698b7be3bf6b28e
Author: Jason Merrill <ja...@redhat.com>
Date: Sat Mar 5 14:44:31 2016 -0500
PR c++/67364
* constexpr.c (cxx_eval_store_expression): Replace
CONSTRUCTOR_ELTS in nested CONSTRUCTORs, too.
diff --git a/gcc/cp/constexpr.c b/gcc/cp/constexpr.c
index c9f9c47..f23e7c9 100644
--- a/gcc/cp/constexpr.c
+++ b/gcc/cp/constexpr.c
@@ -2939,39 +2939,34 @@ cxx_eval_store_expression (const constexpr_ctx *ctx, tree t,
/* Don't share a CONSTRUCTOR that might be changed later. */
init = unshare_expr (init);
if (target == object)
+ /* The hash table might have moved since the get earlier. */
+ valp = ctx->values->get (object);
+
+ if (TREE_CODE (init) == CONSTRUCTOR)
{
- /* The hash table might have moved since the get earlier. */
- valp = ctx->values->get (object);
- if (TREE_CODE (init) == CONSTRUCTOR)
- {
- /* An outer ctx->ctor might be pointing to *valp, so replace
- its contents. */
- CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init);
- TREE_CONSTANT (*valp) = TREE_CONSTANT (init);
- TREE_SIDE_EFFECTS (*valp) = TREE_SIDE_EFFECTS (init);
- }
- else
- *valp = init;
+ /* An outer ctx->ctor might be pointing to *valp, so replace
+ its contents. */
+ CONSTRUCTOR_ELTS (*valp) = CONSTRUCTOR_ELTS (init);
+ TREE_CONSTANT (*valp) = TREE_CONSTANT (init);
+ TREE_SIDE_EFFECTS (*valp) = TREE_SIDE_EFFECTS (init);
}
else
- {
- *valp = init;
+ *valp = init;
- /* Update TREE_CONSTANT and TREE_SIDE_EFFECTS on enclosing
- CONSTRUCTORs. */
- tree elt;
- unsigned i;
- bool c = TREE_CONSTANT (init);
- bool s = TREE_SIDE_EFFECTS (init);
- if (!c || s)
- FOR_EACH_VEC_SAFE_ELT (ctors, i, elt)
- {
- if (!c)
- TREE_CONSTANT (elt) = false;
- if (s)
- TREE_SIDE_EFFECTS (elt) = true;
- }
- }
+ /* Update TREE_CONSTANT and TREE_SIDE_EFFECTS on enclosing
+ CONSTRUCTORs, if any. */
+ tree elt;
+ unsigned i;
+ bool c = TREE_CONSTANT (init);
+ bool s = TREE_SIDE_EFFECTS (init);
+ if (!c || s)
+ FOR_EACH_VEC_SAFE_ELT (ctors, i, elt)
+ {
+ if (!c)
+ TREE_CONSTANT (elt) = false;
+ if (s)
+ TREE_SIDE_EFFECTS (elt) = true;
+ }
release_tree_vector (ctors);
if (*non_constant_p)
diff --git a/gcc/testsuite/g++.dg/cpp0x/constexpr-aggr3.C b/gcc/testsuite/g++.dg/cpp0x/constexpr-aggr3.C
new file mode 100644
index 0000000..547dec4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/cpp0x/constexpr-aggr3.C
@@ -0,0 +1,30 @@
+// PR c++/67364
+// { dg-do compile { target c++11 } }
+
+template <typename Xn>
+struct tuple {
+ Xn storage_;
+
+ constexpr tuple(Xn const& xn)
+ : storage_(xn)
+ { }
+
+ template <typename ...dummy>
+ constexpr tuple(tuple const& other)
+ : storage_(other.storage_)
+ { }
+
+ template <typename ...dummy>
+ constexpr tuple(tuple& other)
+ : tuple(const_cast<tuple const&>(other))
+ { }
+};
+
+template <typename T>
+struct wrapper { T value; };
+
+template <typename T>
+constexpr wrapper<T> wrap(T t) { return {t}; }
+
+constexpr wrapper<tuple<int>> t = wrap(tuple<int>{2});
+static_assert(t.value.storage_ == 2, "");