This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
C++ PATCH: PR 10300
- From: Mark Mitchell <mark at codesourcery dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Sun, 13 Apr 2003 10:54:40 -0700
- Subject: C++ PATCH: PR 10300
- Reply-to: mark at codesourcery dot com
Here is the PR c++/10300 patch for the mainline.
Tested on i686-pc-linux-gnu, applied on the mainline.
--
Mark Mitchell
CodeSourcery, LLC
mark at codesourcery dot com
2003-04-12 Mark Mitchell <mark at codesourcery dot com>
PR c++/10300
* init.c (build_new_1): Reorganize.
2003-04-13 Mark Mitchell <mark at codesourcery dot com>
PR c++/10300
* g++.dg/init/new5.C: New test.
Index: cp/init.c
===================================================================
RCS file: /cvs/gcc/gcc/gcc/cp/init.c,v
retrieving revision 1.315
diff -c -5 -p -r1.315 init.c
*** cp/init.c 16 Mar 2003 14:36:42 -0000 1.315
--- cp/init.c 13 Apr 2003 17:50:44 -0000
*************** get_cookie_size (type)
*** 2152,2168 ****
static tree
build_new_1 (exp)
tree exp;
{
tree placement, init;
! tree type, true_type, size, rval, t;
tree full_type;
tree outer_nelts = NULL_TREE;
tree nelts = NULL_TREE;
! tree alloc_call, alloc_expr, alloc_node;
tree alloc_fn;
- tree cookie_expr, init_expr;
int has_array = 0;
enum tree_code code;
int nothrow, check_new;
/* Nonzero if the user wrote `::new' rather than just `new'. */
int globally_qualified_p;
--- 2152,2179 ----
static tree
build_new_1 (exp)
tree exp;
{
tree placement, init;
! tree true_type, size, rval, t;
! /* The type of the new-expression. (This type is always a pointer
! type.) */
! tree pointer_type;
! /* The type pointed to by POINTER_TYPE. */
! tree type;
! /* The type being allocated. For "new T[...]" this will be an
! ARRAY_TYPE. */
tree full_type;
+ /* A pointer type pointing to to the FULL_TYPE. */
+ tree full_pointer_type;
tree outer_nelts = NULL_TREE;
tree nelts = NULL_TREE;
! tree alloc_call, alloc_expr;
! /* The address returned by the call to "operator new". This node is
! a VAR_DECL and is therefore reusable. */
! tree alloc_node;
tree alloc_fn;
int has_array = 0;
enum tree_code code;
int nothrow, check_new;
/* Nonzero if the user wrote `::new' rather than just `new'. */
int globally_qualified_p;
*************** build_new_1 (exp)
*** 2173,2182 ****
--- 2184,2201 ----
tree cookie_size = NULL_TREE;
/* True if the function we are calling is a placement allocation
function. */
bool placement_allocation_fn_p;
tree args = NULL_TREE;
+ /* True if the storage must be initialized, either by a constructor
+ or due to an explicit new-intiailizer. */
+ bool is_initialized;
+ /* The address of the thing allocated, not including any cookie. In
+ particular, if an array cookie is in use, DATA_ADDR is the
+ address of the first array element. This node is a VAR_DECL, and
+ is therefore reusable. */
+ tree data_addr;
placement = TREE_OPERAND (exp, 0);
type = TREE_OPERAND (exp, 1);
init = TREE_OPERAND (exp, 2);
globally_qualified_p = NEW_EXPR_USE_GLOBAL (exp);
*************** build_new_1 (exp)
*** 2216,2225 ****
--- 2235,2251 ----
}
if (abstract_virtuals_error (NULL_TREE, true_type))
return error_mark_node;
+ is_initialized = (TYPE_NEEDS_CONSTRUCTING (type) || init);
+ if (CP_TYPE_CONST_P (true_type) && !is_initialized)
+ {
+ error ("uninitialized const in `new' of `%#T'", true_type);
+ return error_mark_node;
+ }
+
size = size_in_bytes (true_type);
if (has_array)
size = size_binop (MULT_EXPR, size, convert (sizetype, nelts));
/* Allocate the object. */
*************** build_new_1 (exp)
*** 2319,2366 ****
So check for a null exception spec on the op new we just called. */
nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn));
check_new = (flag_check_new || nothrow) && ! use_java_new;
! alloc_expr = alloc_call;
!
! if (cookie_size)
! /* Adjust so we're pointing to the start of the object. */
! alloc_expr = build (PLUS_EXPR, TREE_TYPE (alloc_expr),
! alloc_expr, cookie_size);
/* While we're working, use a pointer to the type we've actually
! allocated. */
! alloc_expr = convert (build_pointer_type (full_type), alloc_expr);
!
! /* Now save the allocation expression so we only evaluate it once. */
! alloc_expr = get_target_expr (alloc_expr);
alloc_node = TREE_OPERAND (alloc_expr, 0);
- /* Now initialize the cookie. */
if (cookie_size)
{
tree cookie;
/* Store the number of bytes allocated so that we can know how
many elements to destroy later. We use the last sizeof
(size_t) bytes to store the number of elements. */
cookie = build (MINUS_EXPR, build_pointer_type (sizetype),
! alloc_node, size_in_bytes (sizetype));
cookie = build_indirect_ref (cookie, NULL);
! cookie_expr = build (MODIFY_EXPR, void_type_node, cookie, nelts);
TREE_SIDE_EFFECTS (cookie_expr) = 1;
}
else
! cookie_expr = NULL_TREE;
/* Now initialize the allocated object. */
! init_expr = NULL_TREE;
! if (TYPE_NEEDS_CONSTRUCTING (type) || init)
{
! init_expr = build_indirect_ref (alloc_node, NULL);
if (init == void_zero_node)
init = build_default_init (full_type, nelts);
else if (init && pedantic && has_array)
pedwarn ("ISO C++ forbids initialization in array new");
--- 2345,2397 ----
So check for a null exception spec on the op new we just called. */
nothrow = TYPE_NOTHROW_P (TREE_TYPE (alloc_fn));
check_new = (flag_check_new || nothrow) && ! use_java_new;
! /* In the simple case, we can stop now. */
! pointer_type = build_pointer_type (type);
! if (!cookie_size && !is_initialized)
! return build_nop (pointer_type, alloc_call);
/* While we're working, use a pointer to the type we've actually
! allocated. Store the result of the call in a variable so that we
! can use it more than once. */
! full_pointer_type = build_pointer_type (full_type);
! alloc_expr = get_target_expr (build_nop (full_pointer_type, alloc_call));
alloc_node = TREE_OPERAND (alloc_expr, 0);
+ rval = NULL_TREE;
if (cookie_size)
{
tree cookie;
+ tree cookie_expr;
+
+ /* Adjust so we're pointing to the start of the object. */
+ data_addr = get_target_expr (build (PLUS_EXPR, full_pointer_type,
+ alloc_node, cookie_size));
/* Store the number of bytes allocated so that we can know how
many elements to destroy later. We use the last sizeof
(size_t) bytes to store the number of elements. */
cookie = build (MINUS_EXPR, build_pointer_type (sizetype),
! data_addr, size_in_bytes (sizetype));
cookie = build_indirect_ref (cookie, NULL);
! cookie_expr = build (MODIFY_EXPR, sizetype, cookie, nelts);
TREE_SIDE_EFFECTS (cookie_expr) = 1;
+ rval = build (COMPOUND_EXPR, void_type_node, data_addr, cookie_expr);
+ data_addr = TREE_OPERAND (data_addr, 0);
}
else
! data_addr = alloc_node;
/* Now initialize the allocated object. */
! if (is_initialized)
{
! tree init_expr;
!
! init_expr = build_indirect_ref (data_addr, NULL);
if (init == void_zero_node)
init = build_default_init (full_type, nelts);
else if (init && pedantic && has_array)
pedwarn ("ISO C++ forbids initialization in array new");
*************** build_new_1 (exp)
*** 2413,2438 ****
{
enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
tree cleanup;
int flags = (LOOKUP_NORMAL
| (globally_qualified_p * LOOKUP_GLOBAL));
- tree delete_node;
-
- if (cookie_size)
- /* Subtract the padding back out to get to the pointer returned
- from operator new. */
- delete_node = fold (build (MINUS_EXPR, TREE_TYPE (alloc_node),
- alloc_node, cookie_size));
- else
- delete_node = alloc_node;
/* The Standard is unclear here, but the right thing to do
! is to use the same method for finding deallocation
! functions that we use for finding allocation functions. */
flags |= LOOKUP_SPECULATIVELY;
! cleanup = build_op_delete_call (dcode, delete_node, size, flags,
(placement_allocation_fn_p
? alloc_call : NULL_TREE));
/* Ack! First we allocate the memory. Then we set our sentry
variable to true, and expand a cleanup that deletes the memory
--- 2444,2460 ----
{
enum tree_code dcode = has_array ? VEC_DELETE_EXPR : DELETE_EXPR;
tree cleanup;
int flags = (LOOKUP_NORMAL
| (globally_qualified_p * LOOKUP_GLOBAL));
/* The Standard is unclear here, but the right thing to do
! is to use the same method for finding deallocation
! functions that we use for finding allocation functions. */
flags |= LOOKUP_SPECULATIVELY;
! cleanup = build_op_delete_call (dcode, alloc_node, size, flags,
(placement_allocation_fn_p
? alloc_call : NULL_TREE));
/* Ack! First we allocate the memory. Then we set our sentry
variable to true, and expand a cleanup that deletes the memory
*************** build_new_1 (exp)
*** 2478,2521 ****
= build (COMPOUND_EXPR, void_type_node, begin,
build (COMPOUND_EXPR, void_type_node, init_expr,
end));
}
}
- }
- else if (CP_TYPE_CONST_P (true_type))
- error ("uninitialized const in `new' of `%#T'", true_type);
! /* Now build up the return value in reverse order. */
! rval = alloc_node;
! if (init_expr)
! rval = build (COMPOUND_EXPR, TREE_TYPE (rval), init_expr, rval);
! if (cookie_expr)
! rval = build (COMPOUND_EXPR, TREE_TYPE (rval), cookie_expr, rval);
!
! if (rval == alloc_node)
! /* If we didn't modify anything, strip the TARGET_EXPR and return the
! (adjusted) call. */
! rval = TREE_OPERAND (alloc_expr, 1);
! else
{
! if (check_new)
! {
! tree ifexp = cp_build_binary_op (NE_EXPR, alloc_node,
! integer_zero_node);
! rval = build_conditional_expr (ifexp, rval, alloc_node);
! }
!
! rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
}
! /* Now strip the outer ARRAY_TYPE, so we return a pointer to the first
! element. */
! rval = convert (build_pointer_type (type), rval);
! return rval;
}
static tree
build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
tree base, maxindex, type;
--- 2500,2530 ----
= build (COMPOUND_EXPR, void_type_node, begin,
build (COMPOUND_EXPR, void_type_node, init_expr,
end));
}
}
! if (rval)
! rval = build (COMPOUND_EXPR, TREE_TYPE (init_expr), rval, init_expr);
! else
! rval = init_expr;
! }
! rval = build (COMPOUND_EXPR, TREE_TYPE (alloc_node), rval, data_addr);
! if (check_new)
{
! tree ifexp = cp_build_binary_op (NE_EXPR, alloc_node, integer_zero_node);
! rval = build_conditional_expr (ifexp, rval, alloc_node);
}
! /* Perform the allocation before anything else, so that ALLOC_NODE
! has been initialized before we start using it. */
! rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
! /* Convert to the final type. */
! return build_nop (pointer_type, rval);
}
static tree
build_vec_delete_1 (base, maxindex, type, auto_delete_vec, use_global_delete)
tree base, maxindex, type;
Index: testsuite/g++.dg/init/new5.C
===================================================================
RCS file: testsuite/g++.dg/init/new5.C
diff -N testsuite/g++.dg/init/new5.C
*** /dev/null 1 Jan 1970 00:00:00 -0000
--- testsuite/g++.dg/init/new5.C 13 Apr 2003 17:50:45 -0000
***************
*** 0 ****
--- 1,18 ----
+ // { dg-do run }
+
+ #include <new>
+
+ void * operator new[](size_t, std::nothrow_t const &) throw()
+ { return NULL; }
+
+ struct X {
+ struct Inner { ~Inner() {} };
+
+ X() {
+ Inner * ic = new (std::nothrow) Inner[1]; // SegFault here
+ }
+ };
+
+ int main() {
+ X table;
+ }