@@ -249,6 +249,7 @@ build_zero_init_1 (tree type, tree nelts
/* Build a constructor to contain the initializations. */
init = build_constructor (type, v);
+ CONSTRUCTOR_ZERO_PADDING_BITS (init) = 1;
}
else if (TREE_CODE (type) == ARRAY_TYPE)
{
@@ -467,7 +468,9 @@ build_value_init_noctor (tree type, tsub
}
/* Build a constructor to contain the zero- initializations. */
- return build_constructor (type, v);
+ tree ret = build_constructor (type, v);
+ CONSTRUCTOR_ZERO_PADDING_BITS (ret) = 1;
+ return ret;
}
}
else if (TREE_CODE (type) == ARRAY_TYPE)
@@ -6421,6 +6421,7 @@ cxx_eval_store_expression (const constex
type = TREE_TYPE (object);
bool no_zero_init = true;
+ bool zero_padding_bits = false;
auto_vec<tree *> ctors;
releasing_vec indexes;
@@ -6433,6 +6434,7 @@ cxx_eval_store_expression (const constex
{
*valp = build_constructor (type, NULL);
CONSTRUCTOR_NO_CLEARING (*valp) = no_zero_init;
+ CONSTRUCTOR_ZERO_PADDING_BITS (*valp) = zero_padding_bits;
}
else if (STRIP_ANY_LOCATION_WRAPPER (*valp),
TREE_CODE (*valp) == STRING_CST)
@@ -6492,8 +6494,10 @@ cxx_eval_store_expression (const constex
}
/* If the value of object is already zero-initialized, any new ctors for
- subobjects will also be zero-initialized. */
+ subobjects will also be zero-initialized. Similarly with zeroing of
+ padding bits. */
no_zero_init = CONSTRUCTOR_NO_CLEARING (*valp);
+ zero_padding_bits = CONSTRUCTOR_ZERO_PADDING_BITS (*valp);
if (code == RECORD_TYPE && is_empty_field (index))
/* Don't build a sub-CONSTRUCTOR for an empty base or field, as they
@@ -6678,6 +6682,7 @@ cxx_eval_store_expression (const constex
{
*valp = build_constructor (type, NULL);
CONSTRUCTOR_NO_CLEARING (*valp) = no_zero_init;
+ CONSTRUCTOR_ZERO_PADDING_BITS (*valp) = zero_padding_bits;
}
new_ctx.ctor = empty_base ? NULL_TREE : *valp;
new_ctx.object = target;
@@ -6719,6 +6724,7 @@ cxx_eval_store_expression (const constex
/* But do make sure we have something in *valp. */
*valp = build_constructor (type, nullptr);
CONSTRUCTOR_NO_CLEARING (*valp) = no_zero_init;
+ CONSTRUCTOR_ZERO_PADDING_BITS (*valp) = zero_padding_bits;
}
}
else if (*valp && TREE_CODE (*valp) == CONSTRUCTOR
@@ -6731,6 +6737,8 @@ cxx_eval_store_expression (const constex
TREE_SIDE_EFFECTS (*valp) = TREE_SIDE_EFFECTS (init);
CONSTRUCTOR_NO_CLEARING (*valp)
= CONSTRUCTOR_NO_CLEARING (init);
+ CONSTRUCTOR_ZERO_PADDING_BITS (*valp)
+ = CONSTRUCTOR_ZERO_PADDING_BITS (init);
}
else
*valp = init;
@@ -0,0 +1,70 @@
+// PR c++/117256
+// { dg-do run { target c++11 } }
+// { dg-options "-O0" }
+
+void *operator new (decltype (sizeof 0), void *p) noexcept { return p; }
+
+struct A { char c; int i; };
+#if __cplusplus >= 201402L
+struct B { A a; constexpr B (char x, int y) : a () { a.c = x; a.i = y; } };
+#else
+struct B { A a; B (char x, int y) : a () { a.c = x; a.i = y; } };
+#endif
+
+[[gnu::noipa]] void
+foo ()
+{
+ unsigned char buf[sizeof (B)];
+ A a1 = A ();
+ __builtin_memcpy (buf, &a1, sizeof (buf));
+ if (buf[1])
+ __builtin_abort ();
+ unsigned char m1 alignas (A) [sizeof (A)];
+ __builtin_memset (m1, -1, sizeof (m1));
+ A *a2 = new (m1) A ();
+ __builtin_memcpy (buf, a2, sizeof (*a2));
+ if (buf[1])
+ __builtin_abort ();
+ B b1 (42, -42);
+ __builtin_memcpy (buf, &b1, sizeof (b1));
+ if (buf[1])
+ __builtin_abort ();
+ unsigned char m2 alignas (B) [sizeof (B)];
+ B *b2 = new (m2) B (1, 2);
+ __builtin_memcpy (buf, b2, sizeof (*b2));
+ if (buf[1])
+ __builtin_abort ();
+#if __cplusplus >= 201402L
+ constexpr B b3 (3, 4);
+ __builtin_memcpy (buf, &b3, sizeof (b3));
+ if (buf[1])
+ __builtin_abort ();
+#endif
+}
+
+[[gnu::noipa]] void
+bar (unsigned char *p)
+{
+ (void) p;
+}
+
+[[gnu::noipa]] void
+baz ()
+{
+ unsigned char buf[256];
+ __builtin_memset (buf, -1, sizeof (buf));
+ bar (buf);
+}
+
+int
+main ()
+{
+ if (__builtin_offsetof (A, c) == 0
+ && __builtin_offsetof (A, i) != 1
+ && __builtin_offsetof (B, a) == 0
+ && sizeof (A) == sizeof (B))
+ {
+ baz ();
+ foo ();
+ }
+}