gcc ChangeLog 2015-10-12 Martin Sebor PR c++/67942 * invoke.texi (-Wplacement-new): Document new option. * gcc/testsuite/g++.dg/warn/Wplacement-new-size.C: New test. gcc/c-family ChangeLog 2015-10-12 Martin Sebor PR c++/67942 * c.opt (-Wplacement-new): New option. gcc/cp ChangeLog 2015-10-12 Martin Sebor PR c++/67942 * cp/init.c (warn_placement_new_too_small): New function. (build_new_1): Call it. iff --git a/gcc/c-family/c.opt b/gcc/c-family/c.opt index 47ba070..5e9d7a3 100644 --- a/gcc/c-family/c.opt +++ b/gcc/c-family/c.opt @@ -760,6 +760,10 @@ Wprotocol ObjC ObjC++ Var(warn_protocol) Init(1) Warning Warn if inherited methods are unimplemented +Wplacement-new +C++ Var(warn_placement_new) Init(1) Warning +Warn for placement new expressions with undefined behavior + Wredundant-decls C ObjC C++ ObjC++ Var(warn_redundant_decls) Warning Warn about multiple declarations of the same object diff --git a/gcc/cp/init.c b/gcc/cp/init.c index 1ed8f6c..9d23fea 100644 --- a/gcc/cp/init.c +++ b/gcc/cp/init.c @@ -2269,6 +2269,183 @@ throw_bad_array_new_length (void) return build_cxx_call (fn, 0, NULL, tf_warning_or_error); } +/* 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 + it does not. SIZE specifies the size needed to construct the object or + array and captures the result of NELTS * sizeof (TYPE). (SIZE could, in + theory, be greater when the array under construction requires a cookie + to store NELTS, but GCC's placement new does not store the cookie. */ +static void +warn_placement_new_too_small (tree type, tree nelts, tree size, tree oper) +{ + const_tree orig_oper = oper; + + /* The number of bytes to add or subtract from the size of the provided + buffer based on an offset into an array or an array element reference. */ + HOST_WIDE_INT adjust = 0; + bool addr_expr = false; + bool use_obj_size = false; + + while (TREE_CODE (oper) == NOP_EXPR) + oper = TREE_OPERAND (oper, 0); + + /* Using a function argument or a (non-array) variable as an argument + to placement new is not checked since it's unknownwhat it might + point to. */ + if (TREE_CODE (oper) == PARM_DECL + || TREE_CODE (oper) == VAR_DECL + || TREE_CODE (oper) == COMPONENT_REF) + return; + + /* Evaluate any constant expressions. */ + size = fold_non_dependent_expr (size); + + /* Handle the common case of array + offset expression when the offset + is a constant. */ + if (TREE_CODE (oper) == POINTER_PLUS_EXPR) + { + /* If the offset is comple-time constant, use it to compute a more + accurate estimate of the size of the buffer. Otherwise, use + the size of the entire array as an optimistic estimate (this + may lead to false negatives). */ + const_tree adj = TREE_OPERAND (oper, 1); + if (CONSTANT_CLASS_P (adj)) + adjust += (HOST_WIDE_INT)tree_to_uhwi (adj); + else + use_obj_size = true; + + oper = TREE_OPERAND (oper, 0); + + while (TREE_CODE (oper) == NOP_EXPR) + oper = TREE_OPERAND (oper, 0); + } + + if (TREE_CODE (oper) == TARGET_EXPR) + oper = TREE_OPERAND (oper, 1); + else if (TREE_CODE (oper) == ADDR_EXPR) { + addr_expr = true; + oper = TREE_OPERAND (oper, 0); + } + + while (TREE_CODE (oper) == NOP_EXPR) + oper = TREE_OPERAND (oper, 0); + + if (TREE_CODE (oper) == ARRAY_REF) + { + // fold_array_ref (oper); + + /* Similar to the offset computed above, see if the array index + is a compile-time constant. If so, and unless the offset was + not a compile-time constant, use the index to determine the + size of the buffer. Otherwise, use the entire array as + an optimistic estimate of the size. */ + const_tree adj = TREE_OPERAND (oper, 1); + if (!use_obj_size && CONSTANT_CLASS_P (adj)) + adjust += tree_to_shwi (adj); + else + { + use_obj_size = true; + adjust = false; + } + + oper = TREE_OPERAND (oper, 0); + } + + /* 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); + + if ((addr_expr || !POINTER_TYPE_P (TREE_TYPE (oper))) + && (TREE_CODE (oper) == VAR_DECL + || TREE_CODE (oper) == FIELD_DECL + || TREE_CODE (oper) == PARM_DECL)) + { + HOST_WIDE_INT bytes_avail; + const char* txt = ""; + + /* When the referenced object is a member of a union, use the size + of the entire union as the size of the buffer. */ + if (TREE_CODE (oper) == FIELD_DECL + && TREE_CODE (DECL_CONTEXT (oper)) == UNION_TYPE) + bytes_avail = tree_to_shwi (TYPE_SIZE_UNIT (DECL_CONTEXT (oper))); + else if (TREE_CODE (oper) == VAR_DECL || use_obj_size) + { + /* Use the size of the entire array object when the expression + refers to a variable or its size depends on an expression + that's not a compile-time constant. */ + bytes_avail = tree_to_shwi (DECL_SIZE_UNIT (oper)); + txt = "at most "; + } + else + bytes_avail = tree_to_shwi (TYPE_SIZE_UNIT (TREE_TYPE (oper))); + + /* 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; + + /* Reduce the size of the buffer by the adjustment computed above + from the offset and/or the index into the array. */ + if (bytes_avail <= abs (adjust)) + bytes_avail = 0; + else if (0 <= adjust) + bytes_avail -= adjust; + else + bytes_avail += adjust; + + /* The minimum amount of space needed for the allocation. This + is an optimistic estimate that makes it possible to detect + placement new invocation for some undersize buffers but not + others. */ + unsigned HOST_WIDE_INT bytes_need; + + if (CONSTANT_CLASS_P (size)) + bytes_need = tree_to_uhwi (size); + else if (nelts && CONSTANT_CLASS_P (nelts)) + bytes_need = tree_to_uhwi (nelts) + * tree_to_uhwi (TYPE_SIZE_UNIT (type)); + else + bytes_need = tree_to_uhwi (TYPE_SIZE_UNIT (type)); + + if (static_cast(bytes_avail) < bytes_need) + { + if (nelts) + if (CONSTANT_CLASS_P (nelts)) + warning_at (EXPR_LOC_OR_LOC (orig_oper, input_location), + OPT_Wplacement_new, + "placement new constructing a%s %ld-byte object " + "of type %<%T[%lu]%> in a region of type %qT " + "that is %s%ld byte%s large", + bytes_need % 10 == 8 ? "n" : "", bytes_need, + type, tree_to_uhwi (nelts), TREE_TYPE (oper), + txt, bytes_avail, bytes_avail == 1 ? "" : "s"); + else + warning_at (EXPR_LOC_OR_LOC (orig_oper, input_location), + OPT_Wplacement_new, + "placement new constructing an array of %ld-byte " + "objects of type %qT in a region of type %qT " + "that is %s%ld byte%s large", + bytes_need, + type, TREE_TYPE (oper), + txt, bytes_avail, bytes_avail == 1 ? "" : "s"); + else + warning_at (EXPR_LOC_OR_LOC (orig_oper, input_location), + OPT_Wplacement_new, + "placement new constructing a%s %ld-byte object " + "of type %qT in a region of type %qT " + "that is %s%ld byte%s large", + bytes_need % 10 == 8 ? "n" : "", bytes_need, + type, TREE_TYPE (oper), + txt, bytes_avail, bytes_avail == 1 ? "" : "s"); + } + } +} + /* Generate code for a new-expression, including calling the "operator new" function, initializing the object, and, if an exception occurs during construction, cleaning up. The arguments are as for @@ -2518,6 +2695,8 @@ build_new_1 (vec **placement, tree type, tree nelts, && (TYPE_PTR_P (TREE_TYPE ((**placement)[0])))) placement_first = (**placement)[0]; + bool member_new_p = false; + /* Allocate the object. */ if (vec_safe_is_empty (*placement) && TYPE_FOR_JAVA (elt_type)) { @@ -2566,11 +2745,13 @@ build_new_1 (vec **placement, tree type, tree nelts, fnname = ansi_opname (array_p ? VEC_NEW_EXPR : NEW_EXPR); - if (!globally_qualified_p + member_new_p = !globally_qualified_p && CLASS_TYPE_P (elt_type) && (array_p ? TYPE_HAS_ARRAY_NEW_OPERATOR (elt_type) - : TYPE_HAS_NEW_OPERATOR (elt_type))) + : TYPE_HAS_NEW_OPERATOR (elt_type)); + + if (member_new_p) { /* Use a class-specific operator new. */ /* If a cookie is required, add some extra space. */ @@ -2645,20 +2826,30 @@ build_new_1 (vec **placement, tree type, tree nelts, /* If we found a simple case of PLACEMENT_EXPR above, then copy it into a temporary variable. */ if (!processing_template_decl - && placement_first != NULL_TREE && TREE_CODE (alloc_call) == CALL_EXPR && call_expr_nargs (alloc_call) == 2 && TREE_CODE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 0))) == INTEGER_TYPE && TYPE_PTR_P (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 1)))) { - tree placement_arg = CALL_EXPR_ARG (alloc_call, 1); + tree placement = CALL_EXPR_ARG (alloc_call, 1); - if (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg))) - || VOID_TYPE_P (TREE_TYPE (TREE_TYPE (placement_arg)))) + if (placement_first != NULL_TREE + && (INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (TREE_TYPE (placement))) + || VOID_TYPE_P (TREE_TYPE (TREE_TYPE (placement))))) { placement_expr = get_target_expr (placement_first); CALL_EXPR_ARG (alloc_call, 1) - = convert (TREE_TYPE (placement_arg), placement_expr); + = convert (TREE_TYPE (placement), placement_expr); + } + + if (!member_new_p + && VOID_TYPE_P (TREE_TYPE (TREE_TYPE (CALL_EXPR_ARG (alloc_call, 1))))) + { + /* Attempt to make the warning point at the operator new argument. */ + if (placement_first) + placement = placement_first; + + warn_placement_new_too_small (orig_type, nelts, size, placement); } } @@ -3066,6 +3257,7 @@ build_new (vec **placement, tree type, tree nelts, else return error_mark_node; } + nelts = mark_rvalue_use (nelts); nelts = cp_save_expr (cp_convert (sizetype, nelts, complain)); } diff --git a/gcc/doc/invoke.texi b/gcc/doc/invoke.texi index 547ee2d..4f89fa1 100644 --- a/gcc/doc/invoke.texi +++ b/gcc/doc/invoke.texi @@ -271,7 +271,7 @@ Objective-C and Objective-C++ Dialects}. -Woverride-init-side-effects @gol -Woverlength-strings -Wpacked -Wpacked-bitfield-compat -Wpadded @gol -Wparentheses -Wpedantic-ms-format -Wno-pedantic-ms-format @gol --Wpointer-arith -Wno-pointer-to-int-cast @gol +-Wplacement-new -Wpointer-arith -Wno-pointer-to-int-cast @gol -Wredundant-decls -Wno-return-local-addr @gol -Wreturn-type -Wsequence-point -Wshadow -Wno-shadow-ivar @gol -Wshift-overflow -Wshift-overflow=@var{n} @gol @@ -4789,6 +4789,13 @@ disables the warnings about non-ISO @code{printf} / @code{scanf} format width specifiers @code{I32}, @code{I64}, and @code{I} used on Windows targets, which depend on the MS runtime. +@item -Wplacement-new +@opindex Wplacement-new +@opindex Wno-placement-new +Warn about placement new expressions with undefined behavior, such as +constructing an object in a buffer that is smaller than the type of +the object. + @item -Wpointer-arith @opindex Wpointer-arith @opindex Wno-pointer-arith diff --git a/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C b/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C new file mode 100644 index 0000000..d7ceb2a --- /dev/null +++ b/gcc/testsuite/g++.dg/warn/Wplacement-new-size.C @@ -0,0 +1,380 @@ +/* { dg-do compile } */ +/* { dg-options "-Wplacement-new -fpermissive" } */ + +typedef __typeof__ (sizeof 0) size_t; + +void* operator new (size_t, void *p) { return p; } +void* operator new[] (size_t, void *p) { return p; } + +static char c; +static char ac1 [1]; +static char ac2 [2]; +static char ac3 [3]; +static char ac4 [4]; +static char ac5 [5]; +static char ac6 [6]; +static char ac7 [7]; +static char ac8 [8]; + +static char ac1_1 [1][1]; +static char ac1_2 [1][2]; +static char ac2_1 [2][1]; +static char ac2_2 [2][2]; + +static short s; +static short as1 [1]; +static short as2 [2]; + +static struct SC { char c; char *pc; void *pv; } sc; +static struct SAC1 { char ac [1]; } sac1; +static struct SAC2 { char ac [2]; } sac2; +static struct SAC3 { char ac [3]; } sac3; +static struct SAC4 { char ac [4]; } sac4; + +static struct SSC { SC sc; int x; } ssc; +static struct SSAC1 { SAC1 sac; } ssac1; +static struct SSAC2 { SAC2 sac; } ssac2; +static struct SSAC3 { SAC3 sac; } ssac3; +static struct SSAC4 { SAC4 sac; } ssac4; + +static struct SSAC4_2 { SSAC4 ssac4_2 [2]; } sssac4_2; + +static union UAC1 { char c; char ac [1]; } uac1; +static union UAC2 { char c; char ac [2]; } uac2; +static union UAC3 { char c; char ac [3]; } uac3; +static union UAC4 { char c; char ac [4]; } uac4; + +static SC fsc () { return SC (); } +static SAC1 fasc1 () { return SAC1 (); } +static SAC2 fasc2 () { return SAC2 (); } +static SAC3 fasc3 () { return SAC3 (); } +static SAC4 fasc4 () { return SAC4 (); } + +static void *r; + +static void* ptr () { return 0; } + +static void test (void *p, int n) +{ + { + void *q = p; + struct { void *p; } s = { p }; + + // Verify that none of function arguments, local or global + // variables, or function return values trigger the warning. + new (p) char; + new (q) char; + new (r) char; + new (s.p) char; + new (ptr ()) char; + + new (p) char [32]; + new (q) char [32]; + new (r) char [32]; + new (s.p) char [32]; + new (ptr ()) char [32]; + + new (&p) char; + new (&q) char; + new (&r) char; + + // Using address of objects, however, must trigger the warning. + new (&p) char [32]; // { dg-warning "placement" } + new (&q) char [32]; // { dg-warning "placement" } + new (&r) char [32]; // { dg-warning "placement" } + } + + enum { N0, N1, N2, N3 }; + + new (&c) char; + + // Warn for the common case when constructing at an offset from + // the beginning of an array that doesn't leave enough space for + // the object. + new (&c + 0) char; // okay + new (&c + n) char; // okay (n is unknown) + new (&c + 1) char; // { dg-warning "placement" } + new (&c + N0) char; + new (&c + N1) char; // { dg-warning "placement" } + + // No warning is issued when constructing an array in space exactly + // its size even though strictly speaking a compiler is allowed to + // add a cookie to the array (gcc does not). + new (&c) char [1]; + new (&c) char [sizeof c]; + new (&c) char [n]; + new (&c) char [1][1]; + new (&c) char [1][1][1]; + new (&c + N1) char [1][1][1]; // { dg-warning "placement" } + + new (&c) char [2]; // { dg-warning "placement" } + new (&c) char [sizeof c + 1]; // { dg-warning "placement" } + new (&c) char [1][2]; // { dg-warning "placement" } + new (&c) char [2][1]; // { dg-warning "placement" } + new (&c) char [n][1]; + new (&c) char [n][2]; // { dg-warning "placement" } + new (&c) char [3]; // { dg-warning "placement" } + new (&c) char [3][1]; // { dg-warning "placement" } + new (&c) char [1][3]; // { dg-warning "placement" } + new (&c) char [4][1]; // { dg-warning "placement" } + new (&c) char [1][4]; // { dg-warning "placement" } + + // Casts must not suppress it. + new ((void*)&c) char [2]; // { dg-warning "placement" } + new ((char*)&c) char [3]; // { dg-warning "placement" } + + new (static_cast(&c)) char [4]; // { dg-warning "placement" } + new (reinterpret_cast(&c)) char [5]; // { dg-warning "placement" } + + new (&c + 0) char [2]; // { dg-warning "placement" } + new (&c + 0) char [3]; // { dg-warning "placement" } + new (&c + 0) char [4]; // { dg-warning "placement" } + + new (&c + 1) char [2]; // { dg-warning "placement" } + new (&c + 1) char [3]; // { dg-warning "placement" } + new (&c + 1) char [4]; // { dg-warning "placement" } + + new (&c + N0) char [1]; + new (&c + N1) char [2]; // { dg-warning "placement" } + + // Warn even though n is unknown since c is too small for char[2] + // regardless of the value of n. + new (&c + n) char [2]; // { dg-warning "placement" } + + new (ac2) char [1]; + new (ac2) char [1][1]; + new (ac2) char [1][2]; + new (ac2) char [2][1]; + new (ac2) char [1][3]; // { dg-warning "placement" } + new (ac2) char [2][2]; // { dg-warning "placement" } + new (ac2) char [3][1]; // { dg-warning "placement" } + + new (ac2 + N0) char [1][1]; + new (ac2 + N0) char [1][2]; + new (ac2 + N1) char [1][2]; // { dg-warning "placement" } + new (ac2 + N1) char [2][1]; // { dg-warning "placement" } + new (ac2 + N2) char [1][1]; // { dg-warning "placement" } + new (ac2 + N2) char [1][2]; // { dg-warning "placement" } + new (ac2 + N2) char [2][1]; // { dg-warning "placement" } + new (ac2 + N2) char [2][2]; // { dg-warning "placement" } + + new (ac8) char [1]; + new (ac8) char [2][2]; + new (ac8) char [2][3]; + new (ac8) char [2][4]; + new (ac8) char [2][5]; // { dg-warning "placement" } + new (ac8) char [2][2][2]; + new (ac8) char [2][2][3]; // { dg-warning "placement" } + + new (&c) int; // { dg-warning "placement" } + + new (&ac1) int; // { dg-warning "placement" } + new (&ac2) int; // { dg-warning "placement" } + new (&ac3) int; // { dg-warning "placement" } + new (&ac4) int; + + // Constructing at an address of an array element. + new (&ac1 [0]) int; // { dg-warning "placement" } + new (&ac2 [0]) int; // { dg-warning "placement" } + new (&ac3 [0]) int; // { dg-warning "placement" } + new (&ac4 [0]) int; + + // ...plus or minus a constant offset. + new (&ac1 [0] + 0) int; // { dg-warning "placement" } + new (&ac2 [0] + 0) int; // { dg-warning "placement" } + new (&ac3 [0] + 0) int; // { dg-warning "placement" } + new (&ac4 [0] + 0) int; + new (&ac4 [1] + 0) int; // { dg-warning "placement" } + new (&ac4 [1] - 1) int; + new (&ac4 [2] - 1) int; // { dg-warning "placement" } + new (&ac4 [2] - 2) int; + new (&ac4 [3] - 1) int; // { dg-warning "placement" } + new (&ac4 [3] - 2) int; // { dg-warning "placement" } + new (&ac4 [3] - 3) int; + new (&ac4 [4] - 1) int; // { dg-warning "placement" } + new (&ac4 [4] - 2) int; // { dg-warning "placement" } + new (&ac4 [4] - 3) int; // { dg-warning "placement" } + new (&ac4 [4] - 4) int; + + new (&ac1 [0] + 1) int; // { dg-warning "placement" } + new (&ac2 [0] + 1) int; // { dg-warning "placement" } + new (&ac3 [0] + 1) int; // { dg-warning "placement" } + new (&ac4 [0] + 1) int; // { dg-warning "placement" } + + new (&ac3 [0] + n) int; // { dg-warning "placement" } + new (&ac4 [0] + n) int; // no warning (n could be zero) + new (&ac4 [1] + n) int; // no warning (n could be negative) + new (&ac4 [2] + n) int; // ditto + new (&ac4 [3] + n) int; // ditto + new (&ac4 [4] + n) int; // ditto + new (&ac4 [4] - n) int; // (or positive) + + new (&c + 0) int; // { dg-warning "placement" } + new (&c + 1) int; // { dg-warning "placement" } + + // Constructing at an offset into the address of an array. + new (&ac1 + 0) int; // { dg-warning "placement" } + new (&ac1 + 1) int; // { dg-warning "placement" } + new (&ac1 + n) int; // { dg-warning "placement" } + new (&ac2 + 0) int; // { dg-warning "placement" } + new (&ac2 + 1) int; // { dg-warning "placement" } + new (&ac2 + n) int; // { dg-warning "placement" } + new (&ac3 + 0) int; // { dg-warning "placement" } + new (&ac3 + 1) int; // { dg-warning "placement" } + + // Even though n below is uknown an array of 3 bytes isn't large + // enugh for an int. + new (&ac3 + n) int; // { dg-warning "placement" } + + new (&ac4 + 0) int; + new (&ac4 + 1) int; // { dg-warning "placement" } + new (&ac4 + n) int; // no warning (n could be zero) + + // Constructing in an array object. + new (ac1) int; // { dg-warning "placement" } + new (ac2) int; // { dg-warning "placement" } + new (ac3) int; // { dg-warning "placement" } + new (ac4) int; + new (ac5) int; + new (ac5 + 0) int; + new (ac5 + 1) int; + new (ac5 + n) int; // no warning (n could be zero) + new (ac5 + 2) int; // { dg-warning "placement" } + new (ac5 + 3) int; // { dg-warning "placement" } + new (ac5 + 4) int; // { dg-warning "placement" } + new (ac5 + 5) int; // { dg-warning "placement" } + + new (ac1_1) char; + new (ac1_1) char[1]; + new (ac1_1) char[n]; // no warning (n is unknown) + new (ac1_1) char[2]; // { dg-warning "placement" } + new (ac1_1) char[3]; // { dg-warning "placement" } + + new (ac1_2) char; + new (ac1_2) char[1]; + new (ac1_2) char[2]; + new (ac1_2) char[3]; // { dg-warning "placement" } + + new (ac2_1) char; + new (ac2_1) char[1]; + new (ac2_1) char[2]; + new (ac2_1) char[3]; // { dg-warning "placement" } + + new (ac2_2) char; + new (ac2_2) char[1]; + new (ac2_2) char[2]; + new (ac2_2) char[2][2]; + + // Even though n below is uknown it can't meaningfully be zero + // (even if zero-size arrays are allowed as an extension, the size + // they are allocated in by placement new is zero). + new (ac1_1) char[n][2]; // { dg-warning "placement" } + new (ac2_2) char[3]; + new (ac2_2) char[3][1]; + new (ac2_2) char[3][2]; // { dg-warning "placement" } + new (ac2_2) char[4]; + new (ac2_2) char[4][1]; + new (ac2_2) char[4][2]; // { dg-warning "placement" } + new (ac2_2) char[5]; // { dg-warning "placement" } + + new (&s) int; // { dg-warning "placement" } + new (&as1) int; // { dg-warning "placement" } + new (&as2) int; + + new (as1) int; // { dg-warning "placement" } + new (as2) int; + + new (&sc.c) int; // { dg-warning "placement" } + new (&sac1.ac) int; // { dg-warning "placement" } + new (&sac2.ac) int; // { dg-warning "placement" } + new (&sac3.ac) int; // { dg-warning "placement" } + new (&sac4.ac) int; + + new (sc.pc) char; + new (sc.pc) int; + new (sc.pc) int[1024]; + new (sc.pc + 0) int; + new (sc.pc + 0) int[2048]; + new (sc.pv) int; + new (sc.pv) char[1024]; + + new (sac1.ac) int; // { dg-warning "placement" } + new (sac2.ac) int; // { dg-warning "placement" } + new (sac3.ac) int; // { dg-warning "placement" } + new (sac4.ac) int; + + new (&ssc.sc) SSC; // { dg-warning "placement" } + new (&ssac1.sac) int; // { dg-warning "placement" } + new (&ssac2.sac) int; // { dg-warning "placement" } + new (&ssac3.sac) int; // { dg-warning "placement" } + new (&ssac4.sac) int; + + new (&sssac4_2) char[sizeof sssac4_2]; + new (&sssac4_2) char[sizeof sssac4_2 + 1]; // { dg-warning "placement" } + + // taking the address of a temporary is allowed with -fpermissive + new (&fsc ().c) int; // { dg-warning "address|placement" } + new (&fasc1 ().ac) int; // { dg-warning "address|placement" } + new (&fasc2 ().ac) int; // { dg-warning "address|placement" } + new (&fasc3 ().ac) int; // { dg-warning "address|placement" } + new (&fasc4 ().ac) int; // { dg-warning "address|placement" } + + new (&uac1) int; // { dg-warning "placement" } + new (&uac2) int; // { dg-warning "placement" } + new (&uac3) int; // { dg-warning "placement" } + new (&uac4) int; + new (&uac4 + 1) int; // { dg-warning "placement" } + + new (&uac1.c) int; // { dg-warning "placement" } + new (&uac2.c) int; // { dg-warning "placement" } + new (&uac3.c) int; // { dg-warning "placement" } + new (&uac4.c) int; + new (&uac4.c + 1) int; // { dg-warning "placement" } +} + + +struct ClassWithMemberNew { + struct Object { int i; } *pobj; + unsigned nobj; + + ClassWithMemberNew (); + void foo (); + + void* operator new (size_t, void*); + void* operator new[] (size_t, void*); +}; + +void ClassWithMemberNew::foo() +{ + for (unsigned i = 0; i != nobj; ++i) + new (pobj + i) Object (); +} + + +struct ClassWithGlobalNew { + int a [4]; + ClassWithGlobalNew (); +}; + +void* operator new (size_t, ClassWithGlobalNew*); +void* operator new[] (size_t, ClassWithGlobalNew*); + +void test_user_defined_placement_new () +{ + { + ClassWithMemberNew x; + + // Expect no diagnostics for placement new expressions with types + // with their own placement operator new since the semantics of + // the operator aren't known. + new (&c) ClassWithMemberNew; + new (&x) ClassWithMemberNew[2]; + } + + { + ClassWithGlobalNew x; + + new (&c) ClassWithGlobalNew; // { dg-warning "placement" } + new (&x) ClassWithGlobalNew[2]; + } +}