]> git.ipfire.org Git - thirdparty/gcc.git/commitdiff
PR c++/69662 - -Wplacement-new on allocated one element array members
authormsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 5 Feb 2016 22:27:37 +0000 (22:27 +0000)
committermsebor <msebor@138bc75d-0d04-0410-961f-82ee72b054a4>
Fri, 5 Feb 2016 22:27:37 +0000 (22:27 +0000)
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.

git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@233190 138bc75d-0d04-0410-961f-82ee72b054a4

gcc/ChangeLog
gcc/c-family/ChangeLog
gcc/c-family/c.opt
gcc/cp/ChangeLog
gcc/cp/init.c
gcc/doc/invoke.texi
gcc/testsuite/ChangeLog
gcc/testsuite/g++.dg/warn/Wplacement-new-size-1.C [new file with mode: 0644]
gcc/testsuite/g++.dg/warn/Wplacement-new-size-2.C [new file with mode: 0644]

index 9e61921fc060cd79f072b7c868a1b2851951dc81..9a51133e00e67334375889360e12ed73dd891304 100644 (file)
@@ -1,3 +1,9 @@
+2016-02-05  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/69662
+       * doc/invoke.texi: Update -Wplacement-new to take an optional
+       argument.
+
 2016-02-06  Richard Henderson  <rth@redhat.com>
 
        PR c/69643
index abe970193ffef4649290e5510824998f21156a39..c4f6bc42a7ca01f85c9148fc66da6486f263b639 100644 (file)
@@ -1,3 +1,9 @@
+2016-02-05  Martin Sebor  <msebor@redhat.com>
+
+       PR c++/69662
+       * c.opt (Warning options): Update -Wplacement-new to take
+       an optional argument.
+
 2016-02-01  Jakub Jelinek  <jakub@redhat.com>
 
        PR preprocessor/69543
index f243744a97885c32f91a652070a286f23e0f801f..04dec78eb8e11b883c661f388cee74916e16fb8a 100644 (file)
@@ -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
index a7f2b34e4250268cd6a1e3f9d6ebc5106c7295f9..427425ae17a9c13057d6f4628bbcc3f4d820e16b 100644 (file)
@@ -1,3 +1,10 @@
+2016-02-05  Martin Sebor  <msebor@redhat.com>
+
+       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  <jason@redhat.com>
 
        PR c++/68948
index 976ada84587752585ec84b1064733832c6cfac7f..cb2e852fdfc5e42458d9a48b2cfd8c4f876adf25 100644 (file)
@@ -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"
index 650099ec1ffa45cffb01b8a09c4ee519d1e6cea6..0a2a6f45d7cf916a84dc48b6885cf04d43b12d8a 100644 (file)
@@ -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
index d8f088d1bd7dd21ecb5080a29346952af42294cf..cce24b4eb2f592511e32a2347d919091f03771e7 100644 (file)
@@ -1,3 +1,9 @@
+2016-02-05  Martin Sebor  <msebor@redhat.com>
+
+       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  <rth@redhat.com>
 
        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 (file)
index 0000000..b549ae1
--- /dev/null
@@ -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 (file)
index 0000000..23d4324
--- /dev/null
@@ -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" }
+}