From 46cb933227a0c1cd1e8fca1c3c7179c3bee41be3 Mon Sep 17 00:00:00 2001 From: Martin Sebor Date: Fri, 5 Feb 2016 22:27:37 +0000 Subject: [PATCH] PR c++/69662 - -Wplacement-new on allocated one element array members gcc/testsuite/ChangeLog: PR c++/69662 * g++.dg/warn/Wplacement-new-size-1.C: New test. * g++.dg/warn/Wplacement-new-size-2.C: New test. gcc/cp/ChangeLog: PR c++/69662 * init.c (find_field_init): New function. (warn_placement_new_too_small): Call it. Handle one-element arrays at ends of structures special. gcc/c-family/ChangeLog: PR c++/69662 * c.opt (Warning options): Update -Wplacement-new to take an optional argument. gcc/ChangeLog: PR c++/69662 * doc/invoke.texi: Update -Wplacement-new to take an optional argument. From-SVN: r233190 --- gcc/ChangeLog | 6 + gcc/c-family/ChangeLog | 6 + gcc/c-family/c.opt | 6 +- gcc/cp/ChangeLog | 7 + gcc/cp/init.c | 91 ++++++-- gcc/doc/invoke.texi | 35 +++- gcc/testsuite/ChangeLog | 6 + .../g++.dg/warn/Wplacement-new-size-1.C | 139 ++++++++++++ .../g++.dg/warn/Wplacement-new-size-2.C | 197 ++++++++++++++++++ 9 files changed, 478 insertions(+), 15 deletions(-) create mode 100644 gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C create mode 100644 gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 9e61921fc06..9a51133e00e 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,9 @@ +2016-02-05 Martin Sebor + + PR c++/69662 + * doc/invoke.texi: Update -Wplacement-new to take an optional + argument. + 2016-02-06 Richard Henderson PR c/69643 diff --git a/gcc/c-family/ChangeLog b/gcc/c-family/ChangeLog index abe970193ff..c4f6bc42a7c 100644 --- a/gcc/c-family/ChangeLog +++ b/gcc/c-family/ChangeLog @@ -1,3 +1,9 @@ +2016-02-05 Martin Sebor + + PR c++/69662 + * c.opt (Warning options): Update -Wplacement-new to take + an optional argument. + 2016-02-01 Jakub Jelinek PR preprocessor/69543 diff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index f243744a978..04dec78eb8e 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -777,7 +777,11 @@ ObjC ObjC++ Var(warn_protocol) Init(1) Warning Warn if inherited methods are unimplemented. Wplacement-new -C++ Var(warn_placement_new) Init(1) Warning +C++ Warning Alias(Wplacement-new=, 1, 0) +Warn for placement new expressions with undefined behavior. + +Wplacement-new= +C++ Joined RejectNegative UInteger Var(warn_placement_new) Init(-1) Warning Warn for placement new expressions with undefined behavior. Wredundant-decls diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index a7f2b34e425..427425ae17a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2016-02-05 Martin Sebor + + PR c++/69662 + * init.c (find_field_init): New function. + (warn_placement_new_too_small): Call it. Handle one-element arrays + at ends of structures special. + 2016-02-05 Jason Merrill PR c++/68948 diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 976ada84587..cb2e852fdfc 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2285,6 +2285,33 @@ throw_bad_array_new_length (void) return build_cxx_call (fn, 0, NULL, tf_warning_or_error); } +/* Attempt to find the initializer for field T in the initializer INIT, + when non-null. Returns the initializer when successful and NULL + otherwise. */ +static tree +find_field_init (tree t, tree init) +{ + if (!init) + return NULL_TREE; + + unsigned HOST_WIDE_INT idx; + tree field, elt; + + /* Iterate over all top-level initializer elements. */ + FOR_EACH_CONSTRUCTOR_ELT (CONSTRUCTOR_ELTS (init), idx, field, elt) + { + /* If the member T is found, return it. */ + if (field == t) + return elt; + + /* Otherwise continue and/or recurse into nested initializers. */ + if (TREE_CODE (elt) == CONSTRUCTOR + && (init = find_field_init (t, elt))) + return init; + } + return NULL_TREE; +} + /* Attempt to verify that the argument, OPER, of a placement new expression refers to an object sufficiently large for an object of TYPE or an array of NELTS of such objects when NELTS is non-null, and issue a warning when @@ -2375,10 +2402,25 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) oper = TREE_OPERAND (oper, 0); } + /* Refers to the declared object that constains the subobject referenced + by OPER. When the object is initialized, makes it possible to determine + the actual size of a flexible array member used as the buffer passed + as OPER to placement new. */ + tree var_decl = NULL_TREE; + /* True when operand is a COMPONENT_REF, to distinguish flexible array + members from arrays of unspecified size. */ + bool compref = TREE_CODE (oper) == COMPONENT_REF; + /* Descend into a struct or union to find the member whose address is being used as the agument. */ while (TREE_CODE (oper) == COMPONENT_REF) - oper = TREE_OPERAND (oper, 1); + { + tree op0 = oper; + while (TREE_CODE (op0 = TREE_OPERAND (op0, 0)) == COMPONENT_REF); + if (TREE_CODE (op0) == VAR_DECL) + var_decl = op0; + oper = TREE_OPERAND (oper, 1); + } if ((addr_expr || !POINTER_TYPE_P (TREE_TYPE (oper))) && (TREE_CODE (oper) == VAR_DECL @@ -2387,7 +2429,7 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) { /* A possibly optimistic estimate of the number of bytes available in the destination buffer. */ - unsigned HOST_WIDE_INT bytes_avail; + unsigned HOST_WIDE_INT bytes_avail = 0; /* True when the estimate above is in fact the exact size of the destination buffer rather than an estimate. */ bool exact_size = true; @@ -2410,20 +2452,45 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) as the optimistic estimate of the available space in it. */ bytes_avail = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (oper))); } + else if (var_decl) + { + /* Constructing into a buffer provided by the flexible array + member of a declared object (which is permitted as a G++ + extension). If the array member has been initialized, + determine its size from the initializer. Otherwise, + the array size is zero. */ + bytes_avail = 0; + + if (tree init = find_field_init (oper, DECL_INITIAL (var_decl))) + bytes_avail = tree_to_uhwi (TYPE_SIZE_UNIT (TREE_TYPE (init))); + } else { /* Bail if neither the size of the object nor its type is known. */ return; } - /* Avoid diagnosing flexible array members (accepted as an extension - and diagnosed with -Wpedantic). - Constructing objects that appear to overflow the C99 equivalent of - flexible array members (i.e., array members of size zero or one) - are diagnosed in C++ since their declaration cannot be diagnosed. */ - if (bytes_avail == 0 && TREE_CODE (TREE_TYPE (oper)) == ARRAY_TYPE) - return; + tree_code oper_code = TREE_CODE (TREE_TYPE (oper)); + if (compref && oper_code == ARRAY_TYPE) + { + /* Avoid diagnosing flexible array members (which are accepted + as an extension and diagnosed with -Wpedantic) and zero-length + arrays (also an extension). + Overflowing construction in one-element arrays is diagnosed + only at level 2. */ + if (bytes_avail == 0 && !var_decl) + return; + + tree nelts = array_type_nelts_top (TREE_TYPE (oper)); + tree nelts_cst = maybe_constant_value (nelts); + if (TREE_CODE (nelts_cst) == INTEGER_CST + && integer_onep (nelts_cst) + && !var_decl + && warn_placement_new < 2) + return; + } + /* The size of the buffer can only be adjusted down but not up. */ gcc_checking_assert (0 <= adjust); @@ -2452,7 +2519,7 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) { if (nelts) if (CONSTANT_CLASS_P (nelts)) - warning_at (loc, OPT_Wplacement_new, + warning_at (loc, OPT_Wplacement_new_, exact_size ? "placement new constructing an object of type " "%<%T [%wu]%> and size %qwu in a region of type %qT " @@ -2464,7 +2531,7 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) TREE_TYPE (oper), bytes_avail); else - warning_at (loc, OPT_Wplacement_new, + warning_at (loc, OPT_Wplacement_new_, exact_size ? "placement new constructing an array of objects " "of type %qT and size %qwu in a region of type %qT " @@ -2475,7 +2542,7 @@ warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) type, bytes_need, TREE_TYPE (oper), bytes_avail); else - warning_at (loc, OPT_Wplacement_new, + warning_at (loc, OPT_Wplacement_new_, exact_size ? "placement new constructing an object of type %qT " "and size %qwu in a region of type %qT and size %qwi" diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 650099ec1ff..0a2a6f45d7c 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -281,7 +281,8 @@ Objective-C and Objective-C++ Dialects}. -Woverride-init-side-effects -Woverlength-strings @gol -Wpacked -Wpacked-bitfield-compat -Wpadded @gol -Wparentheses -Wno-pedantic-ms-format @gol --Wplacement-new -Wpointer-arith -Wno-pointer-to-int-cast @gol +-Wplacement-new -Wplacement-new=@var{n} @gol +-Wpointer-arith -Wno-pointer-to-int-cast @gol -Wno-pragmas -Wredundant-decls -Wno-return-local-addr @gol -Wreturn-type -Wsequence-point -Wshadow -Wno-shadow-ivar @gol -Wshift-overflow -Wshift-overflow=@var{n} @gol @@ -4894,6 +4895,7 @@ width specifiers @code{I32}, @code{I64}, and @code{I} used on Windows targets, which depend on the MS runtime. @item -Wplacement-new +@itemx -Wplacement-new=@var{n} @opindex Wplacement-new @opindex Wno-placement-new Warn about placement new expressions with undefined behavior, such as @@ -4906,7 +4908,36 @@ char buf [64]; new (buf) int[64]; @end smallexample This warning is enabled by default. - + +@table @gcctabopt +@item -Wplacement-new=1 +This is the default warning level of @option{-Wplacement-new}. At this +level the warning is not issued for some strictly undefined constructs that +GCC allows as extensions for compatibility with legacy code. For example, +the following @code{new} expression is not diagnosed at this level even +though it has undefined behavior according to the C++ standard because +it writes past the end of the one-element array. +@smallexample +struct S @{ int n, a[1]; @}; +S *s = (S *)malloc (sizeof *s + 31 * sizeof s->a[0]); +new (s->a)int [32](); +@end smallexample + +@item -Wplacement-new=2 +At this level, in addition to diagnosing all the same constructs as at level +1, a diagnostic is also issued for placement new expressions that construct +an object in the last member of structure whose type is an array of a single +element and whose size is less than the size of the object being constructed. +While the previous example would be diagnosed, the following construct makes +use of the flexible member array extension to avoid the warning at level 2. +@smallexample +struct S @{ int n, a[]; @}; +S *s = (S *)malloc (sizeof *s + 32 * sizeof s->a[0]); +new (s->a)int [32](); +@end smallexample + +@end table + @item -Wpointer-arith @opindex Wpointer-arith @opindex Wno-pointer-arith diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index d8f088d1bd7..cce24b4eb2f 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,9 @@ +2016-02-05 Martin Sebor + + PR c++/69662 + * g++.dg/warn/Wplacement-new-size-1.C: New test. + * g++.dg/warn/Wplacement-new-size-2.C: New test. + 2016-02-06 Richard HEnderson PR c/69643 diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C new file mode 100644 index 00000000000..b549ae18e89 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C @@ -0,0 +1,139 @@ +// PR c++/69662 - -Wplacement-new on allocated one element array members +// Exercising the more permissive -Wplacement-new=1. The difference +// between -Wplacement-new=1 is denoted by "no warning at level 1" in +// the comments below. +// { dg-do compile } +// { dg-options "-Wno-pedantic -Wplacement-new=1" } + +typedef __typeof__ (sizeof 0) size_t; + +void* operator new (size_t, void *p) { return p; } +void* operator new[] (size_t, void *p) { return p; } + +struct Ax { char n, a []; }; +struct A0 { char n, a [0]; }; +struct A1 { char n, a [1]; }; +struct A2 { char n, a [2]; }; + +typedef __INT16_TYPE__ Int16; +typedef __INT32_TYPE__ Int32; + +void fAx (Ax *px, Ax &rx) +{ + Ax ax; + new (ax.a) Int32; // { dg-warning "placement" } + new (px->a) Int32; + new (rx.a) Int32; +} + +void fAx2 () +{ + Ax ax2 = { 1, { 2, 3 } }; + + new (ax2.a) Int16; + new (ax2.a) Int32; // { dg-warning "placement" } +} + +void fA0 (A0 *p0, A0 &r0) +{ + A0 a0; + new (a0.a) Int32; // { dg-warning "placement" } + new (p0->a) Int32; + new (r0.a) Int32; +} + +void fA1 (A1 *p1, A1 &r1) +{ + A1 a1; + new (a1.a) Int32; // { dg-warning "placement" } + new (p1->a) Int32; // no warning at level 1 + new (r1.a) Int32; // no warning at level 1 +} + +void fA2 (A2 *p2, A2 &r2) +{ + A2 a2; + new (a2.a) Int32; // { dg-warning "placement" } + new (p2->a) Int32; // { dg-warning "placement" } + new (r2.a) Int32; // { dg-warning "placement" } +} + +struct BAx { int i; Ax ax; }; +struct BA0 { int i; A0 a0; }; +struct BA1 { int i; A1 a1; }; +struct BA2 { int i; A2 a2; }; + +void fBx (BAx *pbx, BAx &rbx) +{ + BAx bax; + new (bax.ax.a) char; // { dg-warning "placement" } + new (bax.ax.a) Int16; // { dg-warning "placement" } + new (bax.ax.a) Int32; // { dg-warning "placement" } + + new (pbx->ax.a) char; + new (rbx.ax.a) char; + new (pbx->ax.a) Int16; + new (rbx.ax.a) Int16; + new (pbx->ax.a) Int32; + new (rbx.ax.a) Int32; + new (pbx->ax.a) int[1234]; + new (rbx.ax.a) int[5678]; +} + +void fBx1 () +{ + BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ { 3 } } }; + + new (bax1.ax.a) char; + new (bax1.ax.a) char[2]; // { dg-warning "placement" } + new (bax1.ax.a) Int16; // { dg-warning "placement" } + new (bax1.ax.a) Int32; // { dg-warning "placement" } +} + +void fBx2 () +{ + BAx bax2 = { 1, /* Ax = */ { 2, /* a[] = */ { 3, 4 } } }; + + new (bax2.ax.a) char; + new (bax2.ax.a) char[2]; + new (bax2.ax.a) char[3]; // { dg-warning "placement" } + new (bax2.ax.a) Int16; + new (bax2.ax.a) char[4]; // { dg-warning "placement" } + new (bax2.ax.a) Int32; // { dg-warning "placement" } +} + +void fBx3 () +{ + BAx bax2 = { 1, /* Ax = */ { 3, /* a[] = */ { 4, 5, 6 } } }; + + new (bax2.ax.a) char; + new (bax2.ax.a) char[2]; + new (bax2.ax.a) Int16; + new (bax2.ax.a) char[3]; + new (bax2.ax.a) char[4]; // { dg-warning "placement" } + new (bax2.ax.a) Int32; // { dg-warning "placement" } +} + +void fB0 (BA0 *pb0, BA0 &rb0) +{ + BA0 ba0; + new (ba0.a0.a) Int32; // { dg-warning "placement" } + new (pb0->a0.a) Int32; + new (rb0.a0.a) Int32; +} + +void fB1 (BA1 *pb1, BA1 &rb1) +{ + BA1 ba1; + new (ba1.a1.a) Int32; // { dg-warning "placement" } + new (pb1->a1.a) Int32; // no warning at level 1 + new (rb1.a1.a) Int32; // no warning at level 1 +} + +void fB2 (BA2 *pb2, BA2 &rb2) +{ + BA2 ba2; + new (ba2.a2.a) Int32; // { dg-warning "placement" } + new (pb2->a2.a) Int32; // { dg-warning "placement" } + new (rb2.a2.a) Int32; // { dg-warning "placement" } +} diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C new file mode 100644 index 00000000000..23d4324ff87 --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C @@ -0,0 +1,197 @@ +// PR c++/69662 - -Wplacement-new on allocated one element array members +// Exercising -Wplacement-new=2. +// { dg-do compile } +// { dg-options "-Wno-pedantic -Wplacement-new=2" } + +typedef __typeof__ (sizeof 0) size_t; + +void* operator new (size_t, void *p) { return p; } +void* operator new[] (size_t, void *p) { return p; } + +struct Ax { char n, a []; }; +struct A0 { char n, a [0]; }; +struct A1 { char n, a [1]; }; +struct A2 { char n, a [2]; }; + +typedef __INT16_TYPE__ Int16; +typedef __INT32_TYPE__ Int32; + +void fAx (Ax *px, Ax &rx) +{ + Ax ax; + + new (ax.a) Int32; // { dg-warning "placement" } + new (ax.a) Int32[1]; // { dg-warning "placement" } + + new (px->a) Int32; + new (px->a) Int32[1]; + + new (rx.a) Int32; + new (rx.a) Int32[2]; +} + +void fAx2 () +{ + // Initialization of non-static objects with flexible array members + // isn't allowed in C and should perhaps be disallowed in C++ as + // well to avoid c++/69696 - incorrect initialization of block-scope + // flexible array members. + Ax ax2 = { 1, { 2, 3 } }; + + new (ax2.a) Int16; + new (ax2.a) Int16[1]; + new (ax2.a) Int16[2]; // { dg-warning "placement" } + new (ax2.a) Int32; // { dg-warning "placement" } + new (ax2.a) Int32[2]; // { dg-warning "placement" } +} + +void fAx3 () +{ + static Ax ax3 = { 1, { 2, 3, 4 } }; + + new (ax3.a) Int16; + new (ax3.a) Int16[1]; + new (ax3.a) Int16[2]; // { dg-warning "placement" } + new (ax3.a) Int32; // { dg-warning "placement" } + new (ax3.a) Int32[1]; // { dg-warning "placement" } +} + +static Ax ax4 = { 1, { 2, 3, 4, 5 } }; + +void fAx4 () +{ + new (ax4.a) Int16; + new (ax4.a) Int16[1]; + new (ax4.a) Int16[2]; + new (ax4.a) Int32; + new (ax4.a) Int32[1]; + new (ax4.a) Int32[2]; // { dg-warning "placement" } +} + +void fA0 (A0 *p0, A0 &r0) +{ + A0 a0; + + new (a0.a) Int32; // { dg-warning "placement" } + new (a0.a) Int32[1]; // { dg-warning "placement" } + + new (p0->a) Int32; + new (p0->a) Int32[1]; + new (p0->a) Int32[2]; + + new (r0.a) Int32; + new (r0.a) Int32[1]; + new (r0.a) Int32[2]; +} + +void fA1 (A1 *p1, A1 &r1) +{ + A1 a1; + + new (a1.a) Int32; // { dg-warning "placement" } + new (a1.a) Int32[1]; // { dg-warning "placement" } + + new (p1->a) Int32; // { dg-warning "placement" } + new (p1->a) Int32[1]; // { dg-warning "placement" } + new (p1->a) Int32[2]; // { dg-warning "placement" } + + new (r1.a) Int32; // { dg-warning "placement" } + new (r1.a) Int32[1]; // { dg-warning "placement" } + new (r1.a) Int32[2]; // { dg-warning "placement" } +} + +void fA2 (A2 *p2, A2 &r2) +{ + A2 a2; + new (a2.a) Int32; // { dg-warning "placement" } + new (a2.a) Int32[1]; // { dg-warning "placement" } + new (a2.a) Int32[2]; // { dg-warning "placement" } + + new (p2->a) Int32; // { dg-warning "placement" } + new (p2->a) Int32[1]; // { dg-warning "placement" } + new (p2->a) Int32[2]; // { dg-warning "placement" } + + new (r2.a) Int32; // { dg-warning "placement" } + new (r2.a) Int32[1]; // { dg-warning "placement" } + new (r2.a) Int32[2]; // { dg-warning "placement" } +} + +struct BAx { int i; Ax ax; }; +struct BA0 { int i; A0 a0; }; +struct BA1 { int i; A1 a1; }; +struct BA2 { int i; A2 a2; }; + +void fBx (BAx *pbx, BAx &rbx) +{ + BAx bax; + new (bax.ax.a) char; // { dg-warning "placement" } + new (bax.ax.a) Int16; // { dg-warning "placement" } + new (bax.ax.a) Int32; // { dg-warning "placement" } + + new (pbx->ax.a) char; + new (rbx.ax.a) char; + new (pbx->ax.a) Int16; + new (rbx.ax.a) Int16; + new (pbx->ax.a) Int32; + new (rbx.ax.a) Int32; + new (pbx->ax.a) int[1234]; + new (rbx.ax.a) int[5678]; +} + +void fBx1 () +{ + BAx bax1 = { 1, /* Ax = */ { 2, /* a[] = */ { 3 } } }; + + new (bax1.ax.a) char; + new (bax1.ax.a) char[2]; // { dg-warning "placement" } + new (bax1.ax.a) Int16; // { dg-warning "placement" } + new (bax1.ax.a) Int32; // { dg-warning "placement" } +} + +void fBx2 () +{ + BAx bax2 = { 1, /* Ax = */ { 2, /* a[] = */ { 3, 4 } } }; + + new (bax2.ax.a) char; + new (bax2.ax.a) char[2]; + new (bax2.ax.a) char[3]; // { dg-warning "placement" } + new (bax2.ax.a) Int16; + new (bax2.ax.a) char[4]; // { dg-warning "placement" } + new (bax2.ax.a) Int32; // { dg-warning "placement" } +} + +void fBx3 () +{ + BAx bax2 = { 1, /* Ax = */ { 3, /* a[] = */ { 4, 5, 6 } } }; + + new (bax2.ax.a) char; + new (bax2.ax.a) char[2]; + new (bax2.ax.a) Int16; + new (bax2.ax.a) char[3]; + new (bax2.ax.a) char[4]; // { dg-warning "placement" } + new (bax2.ax.a) Int32; // { dg-warning "placement" } +} + +void fB0 (BA0 *pb0, BA0 &rb0) +{ + BA0 ba0; + new (ba0.a0.a) Int32; // { dg-warning "placement" } + new (pb0->a0.a) Int32; + new (rb0.a0.a) Int32; +} + +void fB1 (BA1 *pb1, BA1 &rb1) +{ + BA1 ba1; + new (ba1.a1.a) Int32; // { dg-warning "placement" } + new (pb1->a1.a) Int32; // { dg-warning "placement" } + new (rb1.a1.a) Int32; // { dg-warning "placement" } +} + +void fB2 (BA2 *pb2, BA2 &rb2) +{ + BA2 ba2; + new (ba2.a2.a) Int32; // { dg-warning "placement" } + new (pb2->a2.a) Int32; // { dg-warning "placement" } + new (rb2.a2.a) Int32; // { dg-warning "placement" } +}