/* In all cases, the initializer is a constant. */
if (init)
- TREE_CONSTANT (init) = 1;
+ {
+ TREE_CONSTANT (init) = 1;
+ TREE_INVARIANT (init) = 1;
+ }
return init;
}
finish_expr_stmt (init);
}
}
- else if (TYPE_NEEDS_CONSTRUCTING (type)
- || (init && TYPE_HAS_CONSTRUCTOR (type)))
+ else if (TYPE_NEEDS_CONSTRUCTING (type))
{
if (explicit
&& TREE_CODE (type) == ARRAY_TYPE
/* member traversal: note it leaves init NULL */
else if (TREE_CODE (type) == REFERENCE_TYPE)
pedwarn ("uninitialized reference member `%D'", member);
+ else if (CP_TYPE_CONST_P (type))
+ pedwarn ("uninitialized member `%D' with `const' type `%T'",
+ member, type);
}
else if (TREE_CODE (init) == TREE_LIST)
/* There was an explicit member initialization. Do some work
TREE_USED (vtbl) = 1;
/* Now compute the address to use when initializing the vptr. */
- vtbl = BINFO_VTABLE (binfo_for);
+ vtbl = unshare_expr (BINFO_VTABLE (binfo_for));
if (TREE_CODE (vtbl) == VAR_DECL)
- {
- vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
- TREE_CONSTANT (vtbl) = 1;
- }
+ vtbl = build1 (ADDR_EXPR, build_pointer_type (TREE_TYPE (vtbl)), vtbl);
return vtbl;
}
TREE_TYPE (vtt_parm),
vtt_parm,
vtt_index);
- vtbl2 = build1 (INDIRECT_REF, TREE_TYPE (vtbl), vtbl2);
+ vtbl2 = build_indirect_ref (vtbl2, NULL);
+ vtbl2 = convert (TREE_TYPE (vtbl), vtbl2);
/* The actual initializer is the VTT value only in the subobject
constructor. In maybe_clone_body we'll substitute NULL for
if (TREE_CODE (type) == ARRAY_TYPE)
{
- /* Must arrange to initialize each element of EXP
- from elements of INIT. */
- tree itype = init ? TREE_TYPE (init) : NULL_TREE;
-
- if (init && !itype)
+ tree itype;
+
+ /* An array may not be initialized use the parenthesized
+ initialization form -- unless the initializer is "()". */
+ if (init && TREE_CODE (init) == TREE_LIST)
{
- /* Handle bad initializers like:
- class COMPLEX {
- public:
- double re, im;
- COMPLEX(double r = 0.0, double i = 0.0) {re = r; im = i;};
- ~COMPLEX() {};
- };
-
- int main(int argc, char **argv) {
- COMPLEX zees(1.0, 0.0)[10];
- }
- */
error ("bad array initializer");
return error_mark_node;
}
+ /* Must arrange to initialize each element of EXP
+ from elements of INIT. */
+ itype = init ? TREE_TYPE (init) : NULL_TREE;
if (cp_type_quals (type) != TYPE_UNQUALIFIED)
TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
if (itype && cp_type_quals (itype) != TYPE_UNQUALIFIED)
- TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype);
+ itype = TREE_TYPE (init) = TYPE_MAIN_VARIANT (itype);
stmt_expr = build_vec_init (exp, NULL_TREE, init,
- init && same_type_p (TREE_TYPE (init),
- TREE_TYPE (exp)));
+ itype && same_type_p (itype,
+ TREE_TYPE (exp)));
TREE_READONLY (exp) = was_const;
TREE_THIS_VOLATILE (exp) = was_volatile;
TREE_TYPE (exp) = type;
{
tree expr;
- if (IS_AGGR_TYPE (TREE_TYPE (decl))
- || TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
+ if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
expr = build_aggr_init (decl, init, flags);
+ else if (CLASS_TYPE_P (TREE_TYPE (decl)))
+ expr = build_special_member_call (decl, complete_ctor_identifier,
+ build_tree_list (NULL_TREE, init),
+ TYPE_BINFO (TREE_TYPE (decl)),
+ LOOKUP_NORMAL|flags);
else
expr = build (INIT_EXPR, TREE_TYPE (decl), decl, init);
to run a new constructor; and catching an exception, where we
have already built up the constructor call so we could wrap it
in an exception region. */;
- else if (TREE_CODE (init) == CONSTRUCTOR
- && TREE_HAS_CONSTRUCTOR (init))
+ else if (BRACE_ENCLOSED_INITIALIZER_P (init))
{
/* A brace-enclosed initializer for an aggregate. */
my_friendly_assert (CP_AGGREGATE_TYPE_P (type), 20021016);
if (TREE_CODE (name) == TEMPLATE_DECL)
return name;
- if (processing_template_decl || uses_template_parms (type))
+ if (dependent_type_p (type) || type_dependent_expression_p (name))
return build_min_nt (SCOPE_REF, type, name);
if (TREE_CODE (name) == TEMPLATE_ID_EXPR)
return error_mark_node;
}
+ if (processing_template_decl)
+ {
+ if (TREE_CODE (orig_name) == TEMPLATE_ID_EXPR)
+ return build_min (SCOPE_REF, TREE_TYPE (member), type, orig_name);
+ else
+ return build_min (SCOPE_REF, TREE_TYPE (member), type, name);
+ }
+
if (TREE_CODE (member) == TYPE_DECL)
{
TREE_USED (member) = 1;
/* And so are variables with a 'const' type -- unless they
are also 'volatile'. */
|| CP_TYPE_CONST_NON_VOLATILE_P (TREE_TYPE (decl)))
+ && TREE_CODE (decl) != PARM_DECL
&& DECL_INITIAL (decl)
&& DECL_INITIAL (decl) != error_mark_node
/* This is invalid if initial value is not constant.
rval = build_min (NEW_EXPR, build_pointer_type (type),
placement, t, init);
NEW_EXPR_USE_GLOBAL (rval) = use_global_new;
+ TREE_SIDE_EFFECTS (rval) = 1;
return rval;
}
/* Wrap it in a NOP_EXPR so warn_if_unused_value doesn't complain. */
rval = build1 (NOP_EXPR, TREE_TYPE (rval), rval);
- TREE_NO_UNUSED_WARNING (rval) = 1;
+ TREE_NO_WARNING (rval) = 1;
return rval;
}
build_new_1 (tree exp)
{
tree placement, init;
- tree true_type, size, rval, t;
+ tree true_type, size, rval;
/* The type of the new-expression. (This type is always a pointer
type.) */
tree pointer_type;
address of the first array element. This node is a VAR_DECL, and
is therefore reusable. */
tree data_addr;
+ tree init_preeval_expr = NULL_TREE;
placement = TREE_OPERAND (exp, 0);
type = TREE_OPERAND (exp, 1);
{
tree class_addr, alloc_decl;
tree class_decl = build_java_class_ref (true_type);
- tree class_size = size_in_bytes (true_type);
static const char alloc_name[] = "_Jv_AllocObject";
+
use_java_new = 1;
+ alloc_decl = NULL;
if (!get_global_value_if_present (get_identifier (alloc_name),
&alloc_decl))
- {\r
+ {
error ("call to Java constructor with `%s' undefined", alloc_name);
return error_mark_node;
}
else if (really_overloaded_fn (alloc_decl))
- {\r
+ {
error ("`%D' should never be overloaded", alloc_decl);
return error_mark_node;
}
class_addr = build1 (ADDR_EXPR, jclass_node, class_decl);
alloc_call = (build_function_call
(alloc_decl,
- tree_cons (NULL_TREE, class_addr,
- build_tree_list (NULL_TREE, class_size))));
+ build_tree_list (NULL_TREE, class_addr)));
}
else
{
placement delete. */
if (placement_allocation_fn_p)
{
- tree inits = NULL_TREE;
- t = TREE_CHAIN (TREE_OPERAND (alloc_call, 1));
- for (; t; t = TREE_CHAIN (t))
- if (TREE_SIDE_EFFECTS (TREE_VALUE (t)))
- {
- tree init;
- TREE_VALUE (t) = stabilize_expr (TREE_VALUE (t), &init);
- if (inits)
- inits = build (COMPOUND_EXPR, void_type_node, inits, init);
- else
- inits = init;
- }
+ tree inits;
+ stabilize_call (alloc_call, &inits);
if (inits)
alloc_expr = build (COMPOUND_EXPR, TREE_TYPE (alloc_expr), inits,
alloc_expr);
data_addr = alloc_node;
}
- /* Now initialize the allocated object. */
+ /* Now initialize the allocated object. Note that we preevaluate the
+ initialization expression, apart from the actual constructor call or
+ assignment--we do this because we want to delay the allocation as long
+ as possible in order to minimize the size of the exception region for
+ placement delete. */
if (is_initialized)
{
+ bool stable;
+
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)
+ else if (init && has_array)
pedwarn ("ISO C++ forbids initialization in array new");
if (has_array)
- init_expr
- = build_vec_init (init_expr,
- cp_build_binary_op (MINUS_EXPR, outer_nelts,
- integer_one_node),
- init, /*from_array=*/0);
+ {
+ init_expr
+ = build_vec_init (init_expr,
+ cp_build_binary_op (MINUS_EXPR, outer_nelts,
+ integer_one_node),
+ init, /*from_array=*/0);
+
+ /* An array initialization is stable because the initialization
+ of each element is a full-expression, so the temporaries don't
+ leak out. */
+ stable = true;
+ }
else if (TYPE_NEEDS_CONSTRUCTING (type))
- init_expr = build_special_member_call (init_expr,
- complete_ctor_identifier,
- init, TYPE_BINFO (true_type),
- LOOKUP_NORMAL);
+ {
+ init_expr = build_special_member_call (init_expr,
+ complete_ctor_identifier,
+ init, TYPE_BINFO (true_type),
+ LOOKUP_NORMAL);
+ stable = stabilize_init (init_expr, &init_preeval_expr);
+ }
else
{
/* We are processing something like `new int (10)', which
if (TREE_CODE (init) == TREE_LIST)
init = build_x_compound_expr_from_list (init, "new initializer");
-
+
else if (TREE_CODE (init) == CONSTRUCTOR
&& TREE_TYPE (init) == NULL_TREE)
- {
- pedwarn ("ISO C++ forbids aggregate initializer to new");
- init = digest_init (type, init, 0);
- }
+ abort ();
init_expr = build_modify_expr (init_expr, INIT_EXPR, init);
+ stable = stabilize_init (init_expr, &init_preeval_expr);
}
if (init_expr == error_mark_node)
{
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,
+ cleanup = build_op_delete_call (dcode, alloc_node, size,
+ globally_qualified_p,
(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
- if sentry is true. Then we run the constructor, and finally
- clear the sentry.
-
- It would be nice to be able to handle this without the sentry
- variable, perhaps with a TRY_CATCH_EXPR, but this doesn't
- work. We allocate the space first, so if there are any
- temporaries with cleanups in the constructor args we need this
- EH region to extend until end of full-expression to preserve
- nesting.
-
- If the backend had some mechanism so that we could force the
- allocation to be expanded after all the other args to the
- constructor, that would fix the nesting problem and we could
- do away with this complexity. But that would complicate other
- things; in particular, it would make it difficult to bail out
- if the allocation function returns null. Er, no, it wouldn't;
- we just don't run the constructor. The standard says it's
- unspecified whether or not the args are evaluated.
-
- FIXME FIXME FIXME inline invisible refs as refs. That way we
- can preevaluate value parameters. */
-
- if (cleanup)
+ if (!cleanup)
+ /* We're done. */;
+ else if (stable)
+ /* This is much simpler if we were able to preevaluate all of
+ the arguments to the constructor call. */
+ init_expr = build (TRY_CATCH_EXPR, void_type_node,
+ init_expr, cleanup);
+ else
+ /* Ack! First we allocate the memory. Then we set our sentry
+ variable to true, and expand a cleanup that deletes the
+ memory if sentry is true. Then we run the constructor, and
+ finally clear the sentry.
+
+ We need to do this because we allocate the space first, so
+ if there are any temporaries with cleanups in the
+ constructor args and we weren't able to preevaluate them, we
+ need this EH region to extend until end of full-expression
+ to preserve nesting. */
{
tree end, sentry, begin;
build (COMPOUND_EXPR, void_type_node, init_expr,
end));
}
+
}
}
else
rval = build (COMPOUND_EXPR, TREE_TYPE (rval), alloc_expr, rval);
}
+ if (init_preeval_expr)
+ rval = build (COMPOUND_EXPR, TREE_TYPE (rval), init_preeval_expr, rval);
+
/* Convert to the final type. */
rval = build_nop (pointer_type, rval);
/* Outermost wrapper: If pointer is null, punt. */
body = fold (build (COND_EXPR, void_type_node,
fold (build (NE_EXPR, boolean_type_node, base,
- integer_zero_node)),
+ convert (TREE_TYPE (base),
+ integer_zero_node))),
body, integer_zero_node));
body = build1 (NOP_EXPR, void_type_node, body);
int use_global_delete = which_delete & 1;
int use_vec_delete = !!(which_delete & 2);
enum tree_code code = use_vec_delete ? VEC_DELETE_EXPR : DELETE_EXPR;
- int flags = LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL);
- return build_op_delete_call (code, addr, virtual_size, flags, NULL_TREE);
+ return build_op_delete_call (code, addr, virtual_size, use_global_delete,
+ NULL_TREE);
}
/* Call the DTOR_KIND destructor for EXP. FLAGS are as for
if (TREE_CODE (type) == POINTER_TYPE)
{
+ bool complete_p = true;
+
type = TYPE_MAIN_VARIANT (TREE_TYPE (type));
if (TREE_CODE (type) == ARRAY_TYPE)
goto handle_array;
- if (VOID_TYPE_P (type)
- /* We don't want to warn about delete of void*, only other
- incomplete types. Deleting other incomplete types
- invokes undefined behavior, but it is not ill-formed, so
- compile to something that would even do The Right Thing
- (TM) should the type have a trivial dtor and no delete
- operator. */
- || !complete_type_or_diagnostic (type, addr, 1)
- || !IS_AGGR_TYPE (type))
+ /* We don't want to warn about delete of void*, only other
+ incomplete types. Deleting other incomplete types
+ invokes undefined behavior, but it is not ill-formed, so
+ compile to something that would even do The Right Thing
+ (TM) should the type have a trivial dtor and no delete
+ operator. */
+ if (!VOID_TYPE_P (type))
{
- /* Call the builtin operator delete. */
- return build_builtin_delete_call (addr);
+ complete_type (type);
+ if (!COMPLETE_TYPE_P (type))
+ {
+ warning ("possible problem detected in invocation of "
+ "delete operator:");
+ cxx_incomplete_type_diagnostic (addr, type, 1);
+ inform ("neither the destructor nor the class-specific "\r
+ "operator delete will be called, even if they are "\r
+ "declared when the class is defined.");
+ complete_p = false;
+ }
}
+ if (VOID_TYPE_P (type) || !complete_p || !IS_AGGR_TYPE (type))
+ /* Call the builtin operator delete. */
+ return build_builtin_delete_call (addr);
if (TREE_SIDE_EFFECTS (addr))
addr = save_expr (addr);
return void_zero_node;
return build_op_delete_call
- (DELETE_EXPR, addr, cxx_sizeof_nowarn (type),
- LOOKUP_NORMAL | (use_global_delete * LOOKUP_GLOBAL),
+ (DELETE_EXPR, addr, cxx_sizeof_nowarn (type), use_global_delete,
NULL_TREE);
}
else
do_delete = build_op_delete_call (DELETE_EXPR,
addr,
cxx_sizeof_nowarn (type),
- LOOKUP_NORMAL,
+ /*global_p=*/false,
NULL_TREE);
/* Call the complete object destructor. */
auto_delete = sfk_complete_destructor;
/* Make sure we have access to the member op delete, even though
we'll actually be calling it from the destructor. */
build_op_delete_call (DELETE_EXPR, addr, cxx_sizeof_nowarn (type),
- LOOKUP_NORMAL, NULL_TREE);
+ /*global_p=*/false, NULL_TREE);
}
expr = build_dtor_call (build_indirect_ref (addr, NULL),