Commit f1dedc31 by Mark Mitchell Committed by Mark Mitchell

cp-tree.def (SUBOBJECT): New tree node.

	* cp-tree.def (SUBOBJECT): New tree node.
	* cp-tree.h (CLEANUP_P): New macro.
	(SUBOBJECT_CLEANUP): Likewise.
	(keep_next_level): Add parameter.
	(get_temp_regvar): Don't declare.
	(emit_base_init): Remove parameter.
	(expand_aggr_init): Rename to build_aggr_init.
	(expand_vec_init): Rename to build_vec_init.
	(do_pushlevel): Remove.
	(do_poplevel): Likewise.
	(finish_cleanup): New function.
	(finish_subobject): Likewise.
	(stmts_are_full_exprs_p): New variable.
	* decl.c (keep_next_level): Add parameter.
	(cp_finish_decl): Use build_aggr_init, not
	expand_aggr_init.  Use finish_expr_stmt to expand the code.
	(expand_static_init): Use tree-generating, not RTL-generating,
	functions to handle the initialization.
	(start_function): Remove dead code.  Always have a momentary
	obstack inside the function, even before hitting the first curly
	brace.
	(cplus_expand_expr_stmt): Move calls to
	expand_{start,end}_target_temps into semantics.c.
	(cp_function): Add stmts_are_full_exprs_p.
	(push_cp_function_context): Save it.
	(pop_cp_function_context): Restore it.
	* decl2.c (get_temp_regvar): Move to init.c.
	(do_static_initialization): Use build_{aggr,vec}_init.
	(do_static_destruction): Fix typo in comment.
	* dump.c (dequeue_and_dump): Handle INIT_EXPR.
	* except.c (expand_throw): Use create_temporary_var.
	* expr.c (cplus_expand_expr): Use build_{aggr,vec}_init.
	* init.c (expand_vec_init_try_block): Remove.
	(expand_vec_init_catch_clause): Likewise.
	(get_temp_regvar): New function.
	(begin_init_stmts): Likewise.
	(finish_init_stmts): Likewise.
	(perform_member_init): Use build_{aggr,vec}_init.  Build up tree
	structure here.
	(emit_base_init): Likewise.  Remove unused parameter.
	(expand_virtual_init): Likewise.
	(expand_cleanup_for_base): Use finish_subobject.
	(expand_aggr_vbase_init_1): Simplify.
	(construct_virtual_bases): Use tree-generating functions to build
	up initialization.
	(expand_aggr_init): Likewise.  Rename to build_aggr_init.
	(expand_default_init): Likewise.
	(expand_aggr_init_1): Likewise.
	(expand_vec_init): Rename to build_vec_init.
	* method.c (do_build_copy_constructor): Use tree-generating
	functions.  Don't call clear_last_expr.
	(do_build_assign_ref): Likewise.
	(synthesize_method): Call clear_last_expr here.
	* parse.y (base_init): Don't call clear_last_expr here.
	(nodecls): Likewise.
	* pt.c (tsubst_expr): Handle a TRY_BLOCK with CLEANUP_P set.
	* semantics.c (do_pushlevel): Move to here.
	(do_poplevel): Likewise.
	(stmts_are_full_exprs_p): New variable.
	(finish_expr_stmt): Handle logic for temoprary cleanup here.
	(finish_for_stmt): Use finish_expr_stmt.
	(finish_cleanup): New function.
	(finish_function_try_block): Fix indentation.
	(finish_subobject): New function.
	(setup_vtbl_ptr): Call keep_next_level here.
	(finish_stmt_expr): Handle a block with no scope inside the
	statement-expression.
	(expand_stmt): Handle a TRY_BLOCK with CLEANUP_P set.  Handle
	SUBOBJECT.
	* tree.c (search_tree): Handle INIT_EXPR.
	(mapcar): Likewise.
	* typeck.c (build_modify_expr): Don't build an RTL_EXPR.
	* typeck2.c (store_init_value): Change expand_aggr_init to
	build_aggr_init in comment.

From-SVN: r28878
parent 1d0e51ba
1999-08-25 Mark Mitchell <mark@codesourcery.com>
* cp-tree.def (SUBOBJECT): New tree node.
* cp-tree.h (CLEANUP_P): New macro.
(SUBOBJECT_CLEANUP): Likewise.
(keep_next_level): Add parameter.
(get_temp_regvar): Don't declare.
(emit_base_init): Remove parameter.
(expand_aggr_init): Rename to build_aggr_init.
(expand_vec_init): Rename to build_vec_init.
(do_pushlevel): Remove.
(do_poplevel): Likewise.
(finish_cleanup): New function.
(finish_subobject): Likewise.
(stmts_are_full_exprs_p): New variable.
* decl.c (keep_next_level): Add parameter.
(cp_finish_decl): Use build_aggr_init, not
expand_aggr_init. Use finish_expr_stmt to expand the code.
(expand_static_init): Use tree-generating, not RTL-generating,
functions to handle the initialization.
(start_function): Remove dead code. Always have a momentary
obstack inside the function, even before hitting the first curly
brace.
(cplus_expand_expr_stmt): Move calls to
expand_{start,end}_target_temps into semantics.c.
(cp_function): Add stmts_are_full_exprs_p.
(push_cp_function_context): Save it.
(pop_cp_function_context): Restore it.
* decl2.c (get_temp_regvar): Move to init.c.
(do_static_initialization): Use build_{aggr,vec}_init.
(do_static_destruction): Fix typo in comment.
* dump.c (dequeue_and_dump): Handle INIT_EXPR.
* except.c (expand_throw): Use create_temporary_var.
* expr.c (cplus_expand_expr): Use build_{aggr,vec}_init.
* init.c (expand_vec_init_try_block): Remove.
(expand_vec_init_catch_clause): Likewise.
(get_temp_regvar): New function.
(begin_init_stmts): Likewise.
(finish_init_stmts): Likewise.
(perform_member_init): Use build_{aggr,vec}_init. Build up tree
structure here.
(emit_base_init): Likewise. Remove unused parameter.
(expand_virtual_init): Likewise.
(expand_cleanup_for_base): Use finish_subobject.
(expand_aggr_vbase_init_1): Simplify.
(construct_virtual_bases): Use tree-generating functions to build
up initialization.
(expand_aggr_init): Likewise. Rename to build_aggr_init.
(expand_default_init): Likewise.
(expand_aggr_init_1): Likewise.
(expand_vec_init): Rename to build_vec_init.
* method.c (do_build_copy_constructor): Use tree-generating
functions. Don't call clear_last_expr.
(do_build_assign_ref): Likewise.
(synthesize_method): Call clear_last_expr here.
* parse.y (base_init): Don't call clear_last_expr here.
(nodecls): Likewise.
* pt.c (tsubst_expr): Handle a TRY_BLOCK with CLEANUP_P set.
* semantics.c (do_pushlevel): Move to here.
(do_poplevel): Likewise.
(stmts_are_full_exprs_p): New variable.
(finish_expr_stmt): Handle logic for temoprary cleanup here.
(finish_for_stmt): Use finish_expr_stmt.
(finish_cleanup): New function.
(finish_function_try_block): Fix indentation.
(finish_subobject): New function.
(setup_vtbl_ptr): Call keep_next_level here.
(finish_stmt_expr): Handle a block with no scope inside the
statement-expression.
(expand_stmt): Handle a TRY_BLOCK with CLEANUP_P set. Handle
SUBOBJECT.
* tree.c (search_tree): Handle INIT_EXPR.
(mapcar): Likewise.
* typeck.c (build_modify_expr): Don't build an RTL_EXPR.
* typeck2.c (store_init_value): Change expand_aggr_init to
build_aggr_init in comment.
1999-08-25 Mark Mitchell <mark@codesourcery.com>
* dump.c (dequeue_and_dump): Dump TARGET_EXPRs.
1999-08-25 Nathan Sidwell <nathan@acm.org>
......
......@@ -229,7 +229,11 @@ DEFTREECODE (CONTINUE_STMT, "continue_stmt", 'e', 0)
DEFTREECODE (SWITCH_STMT, "switch_stmt", 'e', 2)
DEFTREECODE (GOTO_STMT, "goto_stmt", 'e', 1)
DEFTREECODE (ASM_STMT, "asm_stmt", 'e', 5)
/* A SUBOBJECT statement marks the point at which a sub-object is
fully constructed. After this point, the SUBOBJECT_CLEANUP must be
run if an exception is thrown before the end of the enclosing
function. */
DEFTREECODE (SUBOBJECT, "subobject", 'e', 1)
DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
DEFTREECODE (CASE_LABEL, "case_label", 'e', 2)
DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
......
......@@ -35,6 +35,7 @@ Boston, MA 02111-1307, USA. */
IDENTIFIER_MARKED (used by search routines).
LOCAL_BINDING_P (in CPLUS_BINDING)
ICS_USER_FLAG (in _CONV)
CLEANUP_P (in TRY_BLOCK)
1: IDENTIFIER_VIRTUAL_P.
TI_PENDING_TEMPLATE_FLAG.
TEMPLATE_PARMS_FOR_INLINE.
......@@ -2141,6 +2142,7 @@ extern int flag_new_for_scope;
#define GOTO_DESTINATION(NODE) TREE_OPERAND (NODE, 0)
#define TRY_STMTS(NODE) TREE_OPERAND (NODE, 0)
#define TRY_HANDLERS(NODE) TREE_OPERAND (NODE, 1)
#define CLEANUP_P(NODE) TREE_LANG_FLAG_0 (NODE)
#define HANDLER_PARMS(NODE) TREE_OPERAND (NODE, 0)
#define HANDLER_BODY(NODE) TREE_OPERAND (NODE, 1)
#define COMPOUND_BODY(NODE) TREE_OPERAND (NODE, 0)
......@@ -2151,6 +2153,7 @@ extern int flag_new_for_scope;
#define ASM_CLOBBERS(NODE) TREE_OPERAND (NODE, 4)
#define DECL_STMT_DECL(NODE) TREE_OPERAND (NODE, 0)
#define STMT_EXPR_STMT(NODE) TREE_OPERAND (NODE, 0)
#define SUBOBJECT_CLEANUP(NODE) TREE_OPERAND (NODE, 0)
/* Nonzero for an ASM_STMT if the assembly statement is volatile. */
#define ASM_VOLATILE_P(NODE) \
......@@ -2841,7 +2844,7 @@ extern void set_identifier_local_value PROTO((tree, tree));
extern int global_bindings_p PROTO((void));
extern int toplevel_bindings_p PROTO((void));
extern int namespace_bindings_p PROTO((void));
extern void keep_next_level PROTO((void));
extern void keep_next_level PROTO((int));
extern int kept_level_p PROTO((void));
extern void declare_parm_level PROTO((void));
extern void declare_pseudo_global_level PROTO((void));
......@@ -3009,7 +3012,6 @@ extern void setup_vtbl_ptr PROTO((void));
extern void mark_inline_for_output PROTO((tree));
extern void clear_temp_name PROTO((void));
extern tree get_temp_name PROTO((tree, int));
extern tree get_temp_regvar PROTO((tree, tree));
extern void finish_anon_union PROTO((tree));
extern tree finish_table PROTO((tree, tree, tree, int));
extern void finish_builtin_type PROTO((tree, const char *,
......@@ -3105,10 +3107,10 @@ extern tree do_friend PROTO((tree, tree, tree, tree, tree, enum overload_flag
/* in init.c */
extern void init_init_processing PROTO((void));
extern void expand_direct_vtbls_init PROTO((tree, tree, int, int, tree));
extern void emit_base_init PROTO((tree, int));
extern void emit_base_init PROTO((tree));
extern void check_base_init PROTO((tree));
extern void expand_member_init PROTO((tree, tree, tree));
extern void expand_aggr_init PROTO((tree, tree, int));
extern tree build_aggr_init PROTO((tree, tree, int));
extern int is_aggr_typedef PROTO((tree, int));
extern int is_aggr_type PROTO((tree, int));
extern tree get_aggr_from_typedef PROTO((tree, int));
......@@ -3119,11 +3121,12 @@ extern tree resolve_offset_ref PROTO((tree));
extern tree decl_constant_value PROTO((tree));
extern tree build_new PROTO((tree, tree, tree, int));
extern tree build_new_1 PROTO((tree));
extern tree expand_vec_init PROTO((tree, tree, tree, tree, int));
extern tree build_vec_init PROTO((tree, tree, tree, tree, int));
extern tree build_x_delete PROTO((tree, int, tree));
extern tree build_delete PROTO((tree, tree, tree, int, int));
extern tree build_vbase_delete PROTO((tree, tree));
extern tree build_vec_delete PROTO((tree, tree, tree, tree, int));
extern tree create_temporary_var PROTO((tree));
/* in input.c */
......@@ -3234,7 +3237,6 @@ extern void mark_class_instantiated PROTO((tree, int));
extern void do_decl_instantiation PROTO((tree, tree, tree));
extern void do_type_instantiation PROTO((tree, tree));
extern tree instantiate_decl PROTO((tree));
extern tree do_poplevel PROTO((void));
extern tree get_bindings PROTO((tree, tree, tree));
extern void add_tree PROTO((tree));
extern void begin_tree PROTO((void));
......@@ -3242,7 +3244,6 @@ extern void end_tree PROTO((void));
extern void add_maybe_template PROTO((tree, tree));
extern void pop_tinst_level PROTO((void));
extern int more_specialized_class PROTO((tree, tree));
extern void do_pushlevel PROTO((void));
extern int is_member_template PROTO((tree));
extern int template_parms_equal PROTO((tree, tree));
extern int comp_template_parms PROTO((tree, tree));
......@@ -3349,10 +3350,12 @@ extern void finish_function_handler_sequence PROTO((tree));
extern tree begin_handler PROTO((void));
extern void finish_handler_parms PROTO((tree));
extern void finish_handler PROTO((tree));
extern void finish_cleanup PROTO((tree, tree));
extern tree begin_compound_stmt PROTO((int));
extern tree finish_compound_stmt PROTO((int, tree));
extern void finish_asm_stmt PROTO((tree, tree, tree, tree, tree));
extern void finish_label_stmt PROTO((tree));
extern void finish_subobject PROTO((tree));
extern tree finish_parenthesized_expr PROTO((tree));
extern tree begin_stmt_expr PROTO((void));
extern tree finish_stmt_expr PROTO((tree, tree));
......@@ -3395,6 +3398,7 @@ extern void expand_body PROTO((tree));
extern void begin_stmt_tree PROTO((tree));
extern void finish_stmt_tree PROTO((tree));
extern int expanding_p;
extern int stmts_are_full_exprs_p;
extern tree last_expr_type;
/* Non-zero if we are presently building a statement tree, rather
than expanding each statement as we encounter it. */
......
......@@ -882,10 +882,15 @@ namespace_bindings_p ()
return b->namespace_p;
}
/* If KEEP is non-zero, make a BLOCK node for the next binding level,
unconditionally. Otherwise, use the normal logic to decide whether
or not to create a BLOCK. */
void
keep_next_level ()
keep_next_level (keep)
int keep;
{
keep_next_level_flag = 1;
keep_next_level_flag = keep;
}
/* Nonzero if the current level needs to have a BLOCK made. */
......@@ -7908,7 +7913,16 @@ cp_finish_decl (decl, init, asmspec_tree, need_pop, flags)
{
emit_line_note (DECL_SOURCE_FILE (decl),
DECL_SOURCE_LINE (decl));
expand_aggr_init (decl, init, flags);
/* We call push_momentary here so that when
finish_expr_stmt clears the momentary obstack it
doesn't destory any momentary expressions we may
have lying around. Although cp_finish_decl is
usually called at the end of a declaration
statement, it may also be called for a temporary
object in the middle of an expression. */
push_momentary ();
finish_expr_stmt (build_aggr_init (decl, init, flags));
pop_momentary ();
}
/* Set this to 0 so we can tell whether an aggregate which
......@@ -8024,6 +8038,8 @@ expand_static_init (decl, init)
{
/* Emit code to perform this initialization but once. */
tree temp;
tree assignment;
tree temp_init;
/* Remember this information until end of file. */
push_obstacks (&permanent_obstack, &permanent_obstack);
......@@ -8058,26 +8074,35 @@ expand_static_init (decl, init)
/* Begin the conditional initialization. */
expand_start_cond (build_binary_op (EQ_EXPR, temp,
integer_zero_node), 0);
expand_start_target_temps ();
/* Do the initialization itself. */
if (TYPE_NEEDS_CONSTRUCTING (TREE_TYPE (decl))
|| (init && TREE_CODE (init) == TREE_LIST))
{
expand_aggr_init (decl, init, 0);
do_pending_stack_adjust ();
}
assignment = build_aggr_init (decl, init, 0);
else if (init)
expand_assignment (decl, init, 0, 0);
/* Set TEMP to 1. */
expand_assignment (temp, integer_one_node, 0, 0);
assignment = build_modify_expr (decl, NOP_EXPR, init);
else
assignment = NULL_TREE;
/* Cleanup any temporaries needed for the initial value. If
destroying one of the temporaries causes an exception to be
thrown, then the object itself has still been fully
constructed. */
expand_end_target_temps ();
/* Once the assignment is complete, set TEMP to 1. Since the
construction of the static object is complete at this point,
we want to make sure TEMP is set to 1 even if a temporary
constructed during the initialization throws an exception
when it is destroyed. So, we combine the initialization and
the assignment to TEMP into a single expression, ensuring
that when we call finish_expr_stmt the cleanups will not be
run until after TEMP is set to 1. */
temp_init = build_modify_expr (temp, NOP_EXPR, integer_one_node);
if (assignment)
{
assignment = tree_cons (NULL_TREE, assignment,
build_tree_list (NULL_TREE,
temp_init));
assignment = build_compound_expr (assignment);
}
else
assignment = temp_init;
finish_expr_stmt (assignment);
/* Use atexit to register a function for destroying this static
variable. */
......@@ -12813,25 +12838,6 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
{
decl1 = declarator;
#if 0
/* What was this testing for, exactly? */
if (! DECL_ARGUMENTS (decl1)
&& !DECL_STATIC_FUNCTION_P (decl1)
&& !DECL_ARTIFICIAL (decl1)
&& DECL_CLASS_SCOPE_P (decl1)
&& TYPE_IDENTIFIER (DECL_CONTEXT (decl1))
&& IDENTIFIER_TEMPLATE (TYPE_IDENTIFIER (DECL_CONTEXT (decl1))))
{
tree binding = binding_for_name (DECL_NAME (decl1),
current_namespace);
cp_error ("redeclaration of `%#D'", decl1);
if (IDENTIFIER_CLASS_VALUE (DECL_NAME (decl1)))
cp_error_at ("previous declaration here", IDENTIFIER_CLASS_VALUE (DECL_NAME (decl1)));
else if (BINDING_VALUE (binding))
cp_error_at ("previous declaration here", BINDING_VALUE (binding));
}
#endif
fntype = TREE_TYPE (decl1);
if (TREE_CODE (fntype) == METHOD_TYPE)
ctype = TYPE_METHOD_BASETYPE (fntype);
......@@ -13162,6 +13168,10 @@ start_function (declspecs, declarator, attrs, pre_parsed_p)
if (! hack_decl_function_context (decl1))
temporary_allocation ();
/* Make sure that we always have a momntary obstack while we're in a
function body. */
push_momentary ();
if (building_stmt_tree ())
begin_stmt_tree (decl1);
......@@ -13856,6 +13866,9 @@ finish_function (lineno, flags, nested)
to the FUNCTION_DECL node itself. */
BLOCK_SUPERCONTEXT (DECL_INITIAL (fndecl)) = fndecl;
/* Undo the call to push_momentary in start_function. */
pop_momentary ();
if (expand_p)
{
int saved_flag_keep_inline_functions =
......@@ -14261,9 +14274,6 @@ void
cplus_expand_expr_stmt (exp)
tree exp;
{
/* Arrange for all temps to disappear. */
expand_start_target_temps ();
exp = require_complete_type_in_void (exp);
if (TREE_CODE (exp) == FUNCTION_DECL)
......@@ -14288,10 +14298,6 @@ cplus_expand_expr_stmt (exp)
go outside the bounds of the type. */
if (exp != error_mark_node)
expand_expr_stmt (break_out_cleanups (exp));
/* Clean up any pending cleanups. This happens when a function call
returns a cleanup-needing value that nobody uses. */
expand_end_target_temps ();
}
/* When a stmt has been parsed, this function is called. */
......@@ -14381,6 +14387,7 @@ struct cp_function
int static_labelno;
int in_function_try_handler;
int expanding_p;
int stmts_are_full_exprs_p;
tree last_tree;
tree last_expr_type;
};
......@@ -14429,10 +14436,15 @@ push_cp_function_context (context)
p->last_tree = last_tree;
p->last_expr_type = last_expr_type;
p->expanding_p = expanding_p;
p->stmts_are_full_exprs_p = stmts_are_full_exprs_p;
/* For now, we always assume we're expanding all the way to RTL
unless we're explicitly doing otherwise. */
expanding_p = 1;
/* Whenever we start a new function, we destroy temporaries in the
usual way. */
stmts_are_full_exprs_p = 1;
}
/* Restore the variables used during compilation of a C++ function. */
......@@ -14479,6 +14491,7 @@ pop_cp_function_context (context)
last_tree = p->last_tree;
last_expr_type = p->last_expr_type;
expanding_p = p->expanding_p;
stmts_are_full_exprs_p = p->stmts_are_full_exprs_p;
free (p);
}
......
......@@ -2077,31 +2077,6 @@ get_temp_name (type, staticp)
return decl;
}
/* Get a variable which we can use for multiple assignments.
It is not entered into current_binding_level, because
that breaks things when it comes time to do final cleanups
(which take place "outside" the binding contour of the function). */
tree
get_temp_regvar (type, init)
tree type, init;
{
tree decl;
decl = build_decl (VAR_DECL, NULL_TREE, type);
TREE_USED (decl) = 1;
DECL_REGISTER (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_RTL (decl) = assign_temp (type, 2, 0, 1);
/* We can expand these without fear, since they cannot need
constructors or destructors. */
expand_expr (build_modify_expr (decl, INIT_EXPR, init),
NULL_RTX, VOIDmode, 0);
return decl;
}
/* Hunts through the global anonymous union ANON_DECL, building
appropriate VAR_DECLs. Stores cleanups on the list of ELEMS, and
returns a VAR_DECL whose size is the same as the size of the
......@@ -3219,9 +3194,10 @@ do_static_initialization (decl, init, sentry, priority)
if (IS_AGGR_TYPE (TREE_TYPE (decl))
|| TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE)
expand_aggr_init (decl, init, 0);
expand_expr (build_aggr_init (decl, init, 0),
const0_rtx, VOIDmode, EXPAND_NORMAL);
else if (TREE_CODE (init) == TREE_VEC)
expand_expr (expand_vec_init (decl, TREE_VEC_ELT (init, 0),
expand_expr (build_vec_init (decl, TREE_VEC_ELT (init, 0),
TREE_VEC_ELT (init, 1),
TREE_VEC_ELT (init, 2), 0),
const0_rtx, VOIDmode, EXPAND_NORMAL);
......@@ -3290,7 +3266,7 @@ do_static_destruction (decl, sentry, priority)
integer_zero_node),
/*exit_flag=*/0);
/* Actually to the destruction. */
/* Actually do the destruction. */
expand_expr_stmt (build_cleanup (decl));
/* Cleanup any deferred pops from function calls. This would be done
......
......@@ -768,6 +768,13 @@ dequeue_and_dump (di)
dump_next_stmt (di, t);
break;
case SUBOBJECT:
dump_stmt (di, t);
if (dump_children_p)
dump_child ("clnp", TREE_OPERAND (t, 0));
dump_next_stmt (di, t);
break;
case INTEGER_CST:
if (TREE_INT_CST_HIGH (t))
dump_int (di, "high", TREE_INT_CST_HIGH (t));
......@@ -798,6 +805,7 @@ dequeue_and_dump (di)
case TRUTH_ANDIF_EXPR:
case TRUTH_ORIF_EXPR:
case INIT_EXPR:
case MODIFY_EXPR:
case COMPONENT_REF:
case COMPOUND_EXPR:
......
......@@ -965,9 +965,7 @@ expand_throw (exp)
ourselves into expand_call. */
if (TREE_SIDE_EFFECTS (exp))
{
tree temp = build_decl (VAR_DECL, NULL_TREE, TREE_TYPE (exp));
DECL_ARTIFICIAL (temp) = 1;
DECL_RTL (temp) = assign_temp (TREE_TYPE (exp), 2, 0, 1);
tree temp = create_temporary_var (TREE_TYPE (exp));
DECL_INITIAL (temp) = exp;
cp_finish_decl (temp, exp, NULL_TREE, 0, LOOKUP_ONLYCONVERTING);
exp = temp;
......
......@@ -204,7 +204,9 @@ cplus_expand_expr (exp, target, tmode, modifier)
init = convert_from_reference (init);
flag_access_control = 0;
expand_aggr_init (slot, init, LOOKUP_ONLYCONVERTING);
expand_expr (build_aggr_init (slot, init,
LOOKUP_ONLYCONVERTING),
target, tmode, EXPAND_NORMAL);
flag_access_control = old_ac;
if (TYPE_NEEDS_DESTRUCTOR (type))
......@@ -237,7 +239,7 @@ cplus_expand_expr (exp, target, tmode, modifier)
case VEC_INIT_EXPR:
return expand_expr
(expand_vec_init
(build_vec_init
(NULL_TREE, TREE_OPERAND (exp, 0),
build_binary_op (MINUS_EXPR, TREE_OPERAND (exp, 2),
integer_one_node),
......
......@@ -57,10 +57,11 @@ static int member_init_ok_or_else PROTO((tree, tree, const char *));
static void expand_virtual_init PROTO((tree, tree));
static tree sort_member_init PROTO((tree));
static tree initializing_context PROTO((tree));
static void expand_vec_init_try_block PROTO((tree));
static void expand_vec_init_catch_clause PROTO((tree, tree, tree, tree));
static tree build_java_class_ref PROTO((tree));
static void expand_cleanup_for_base PROTO((tree, tree));
static tree get_temp_regvar PROTO((tree, tree));
static void begin_init_stmts PROTO((tree *, tree *));
static tree finish_init_stmts PROTO((tree, tree));
/* Cache the identifier nodes for the magic field of a new cookie. */
static tree nc_nelts_field_id;
......@@ -119,6 +120,7 @@ expand_direct_vtbls_init (real_binfo, binfo, init_self, can_elide, addr)
tree binfos = BINFO_BASETYPES (binfo);
int i, n_baselinks = real_binfos ? TREE_VEC_LENGTH (real_binfos) : 0;
push_momentary ();
for (i = 0; i < n_baselinks; i++)
{
tree real_base_binfo = TREE_VEC_ELT (real_binfos, i);
......@@ -140,6 +142,7 @@ expand_direct_vtbls_init (real_binfo, binfo, init_self, can_elide, addr)
tree base_ptr = convert_pointer_to_real (binfo, addr);
expand_virtual_init (real_binfo, base_ptr);
}
pop_momentary ();
}
/* 348 - 351 */
......@@ -153,8 +156,6 @@ perform_member_init (member, name, init, explicit)
tree decl;
tree type = TREE_TYPE (member);
expand_start_target_temps ();
decl = build_component_ref (current_class_ref, name, NULL_TREE, explicit);
/* Deal with this here, as we will get confused if we try to call the
......@@ -164,7 +165,7 @@ perform_member_init (member, name, init, explicit)
{
init = build (INIT_EXPR, type, decl, TREE_VALUE (init));
TREE_SIDE_EFFECTS (init) = 1;
expand_expr_stmt (init);
finish_expr_stmt (init);
}
else if (TYPE_NEEDS_CONSTRUCTING (type)
|| (init && TYPE_HAS_CONSTRUCTOR (type)))
......@@ -181,11 +182,12 @@ perform_member_init (member, name, init, explicit)
&& TREE_CODE (TREE_TYPE (TREE_VALUE (init))) == ARRAY_TYPE)
{
/* Initialization of one array from another. */
expand_vec_init (TREE_OPERAND (decl, 1), decl,
array_type_nelts (type), TREE_VALUE (init), 1);
finish_expr_stmt
(build_vec_init (TREE_OPERAND (decl, 1), decl,
array_type_nelts (type), TREE_VALUE (init), 1));
}
else
expand_aggr_init (decl, init, 0);
finish_expr_stmt (build_aggr_init (decl, init, 0));
}
else
{
......@@ -205,7 +207,7 @@ perform_member_init (member, name, init, explicit)
for constructors and such. */
tree e = build (CONSTRUCTOR, type, NULL_TREE, NULL_TREE);
TREE_SIDE_EFFECTS (e) = 1;
expand_expr_stmt (build (INIT_EXPR, type, decl, e));
finish_expr_stmt (build (INIT_EXPR, type, decl, e));
}
else if (TREE_CODE (type) == REFERENCE_TYPE)
cp_error ("default-initialization of `%#D', which has reference type",
......@@ -231,12 +233,9 @@ perform_member_init (member, name, init, explicit)
}
if (init)
expand_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
}
expand_end_target_temps ();
free_temp_slots ();
if (TYPE_NEEDS_DESTRUCTOR (type))
{
tree expr;
......@@ -251,7 +250,7 @@ perform_member_init (member, name, init, explicit)
LOOKUP_NONVIRTUAL|LOOKUP_DESTRUCTOR, 0);
if (expr != error_mark_node)
add_partial_entry (expr);
finish_subobject (expr);
pop_obstacks ();
}
......@@ -508,9 +507,8 @@ sort_base_init (t, rbase_ptr, vbase_ptr)
extern tree base_init_expr;
void
emit_base_init (t, immediately)
emit_base_init (t)
tree t;
int immediately;
{
tree member;
tree mem_init_list;
......@@ -518,27 +516,8 @@ emit_base_init (t, immediately)
tree t_binfo = TYPE_BINFO (t);
tree binfos = BINFO_BASETYPES (t_binfo);
int i, n_baseclasses = binfos ? TREE_VEC_LENGTH (binfos) : 0;
tree expr = NULL_TREE;
if (! immediately)
{
int momentary;
do_pending_stack_adjust ();
/* Make the RTL_EXPR node temporary, not momentary,
so that rtl_expr_chain doesn't become garbage. */
momentary = suspend_momentary ();
expr = make_node (RTL_EXPR);
resume_momentary (momentary);
start_sequence_for_rtl_expr (expr);
}
if (write_symbols == NO_DEBUG)
/* As a matter of principle, `start_sequence' should do this. */
emit_note (0, -1);
else
/* Always emit a line number note so we can step into constructors. */
emit_line_note_force (DECL_SOURCE_FILE (current_function_decl),
DECL_SOURCE_LINE (current_function_decl));
tree stmt_expr;
tree compound_stmt;
mem_init_list = sort_member_init (t);
current_member_init_list = NULL_TREE;
......@@ -546,6 +525,8 @@ emit_base_init (t, immediately)
sort_base_init (t, &rbase_init_list, &vbase_init_list);
current_base_init_list = NULL_TREE;
begin_init_stmts (&stmt_expr, &compound_stmt);
/* First, initialize the virtual base classes, if we are
constructing the most-derived object. */
if (TYPE_USES_VIRTUAL_BASECLASSES (t))
......@@ -579,15 +560,10 @@ emit_base_init (t, immediately)
if (init != void_list_node)
{
expand_start_target_temps ();
member = convert_pointer_to_real (base_binfo, current_class_ptr);
expand_aggr_init_1 (base_binfo, NULL_TREE,
build_indirect_ref (member, NULL_PTR), init,
LOOKUP_NORMAL);
expand_end_target_temps ();
free_temp_slots ();
}
expand_cleanup_for_base (base_binfo, NULL_TREE);
......@@ -665,36 +641,12 @@ emit_base_init (t, immediately)
cp_error ("field `%D' not in immediate context", field);
}
#if 0
/* It turns out if you have an anonymous union in the
class, a member from it can end up not being on the
list of fields (rather, the type is), and therefore
won't be seen by the for loop above. */
/* The code in this for loop is derived from a general loop
which had this check in it. Theoretically, we've hit
every initialization for the list of members in T, so
we shouldn't have anything but these left in this list. */
my_friendly_assert (DECL_FIELD_CONTEXT (field) != t, 351);
#endif
perform_member_init (field, name, init, 1);
}
mem_init_list = TREE_CHAIN (mem_init_list);
}
if (! immediately)
{
do_pending_stack_adjust ();
my_friendly_assert (base_init_expr == 0, 207);
base_init_expr = expr;
TREE_TYPE (expr) = void_type_node;
RTL_EXPR_RTL (expr) = const0_rtx;
RTL_EXPR_SEQUENCE (expr) = get_insns ();
rtl_expr_chain = tree_cons (NULL_TREE, expr, rtl_expr_chain);
end_sequence ();
TREE_SIDE_EFFECTS (expr) = 1;
}
base_init_expr = finish_init_stmts (stmt_expr, compound_stmt);
/* All the implicit try blocks we built up will be zapped
when we come to a real binding contour boundary. */
......@@ -745,7 +697,7 @@ expand_virtual_init (binfo, decl)
/* Have to convert VTBL since array sizes may be different. */
vtbl = convert_force (TREE_TYPE (vtbl_ptr), vtbl, 0);
expand_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
finish_expr_stmt (build_modify_expr (vtbl_ptr, NOP_EXPR, vtbl));
}
/* If an exception is thrown in a constructor, those base classes already
......@@ -778,7 +730,7 @@ expand_cleanup_for_base (binfo, flag)
expr, integer_zero_node));
pop_obstacks ();
add_partial_entry (expr);
finish_subobject (expr);
}
/* Subroutine of `expand_aggr_vbase_init'.
......@@ -792,15 +744,10 @@ expand_aggr_vbase_init_1 (binfo, exp, addr, init_list)
tree init = purpose_member (binfo, init_list);
tree ref = build_indirect_ref (addr, NULL_PTR);
expand_start_target_temps ();
if (init)
init = TREE_VALUE (init);
/* Call constructors, but don't set up vtables. */
expand_aggr_init_1 (binfo, exp, ref, init, LOOKUP_COMPLAIN);
expand_end_target_temps ();
free_temp_slots ();
}
/* Construct the virtual base-classes of THIS_REF (whose address is
......@@ -818,23 +765,32 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
{
tree vbases;
tree result;
tree if_stmt;
/* If there are no virtual baseclasses, we shouldn't even be here. */
my_friendly_assert (TYPE_USES_VIRTUAL_BASECLASSES (type), 19990621);
/* First set the pointers in our object that tell us where to find
our virtual baseclasses. */
expand_start_cond (flag, 0);
if_stmt = begin_if_stmt ();
finish_if_stmt_cond (flag, if_stmt);
result = init_vbase_pointers (type, this_ptr);
/* The RESULT will contain entries on the momentary obstack. They
must live until the end of this function; we use them in the loop
below. */
push_momentary ();
if (result)
expand_expr_stmt (build_compound_expr (result));
expand_end_cond ();
finish_expr_stmt (build_compound_expr (result));
finish_then_clause (if_stmt);
finish_if_stmt ();
/* Now, run through the baseclasses, initializing each. */
for (vbases = CLASSTYPE_VBASECLASSES (type); vbases;
vbases = TREE_CHAIN (vbases))
{
tree tmp = purpose_member (vbases, result);
tree inner_if_stmt;
tree compound_stmt;
/* If there are virtual base classes with destructors, we need to
emit cleanups to destroy them if an exception is thrown during
......@@ -850,14 +806,21 @@ construct_virtual_bases (type, this_ref, this_ptr, init_list, flag)
in the outer block.) We trust the back-end to figure out
that the FLAG will not change across initializations, and
avoid doing multiple tests. */
expand_start_cond (flag, 0);
inner_if_stmt = begin_if_stmt ();
finish_if_stmt_cond (flag, inner_if_stmt);
compound_stmt = begin_compound_stmt (/*has_no_scope=*/1);
expand_aggr_vbase_init_1 (vbases, this_ref,
TREE_OPERAND (TREE_VALUE (tmp), 0),
init_list);
expand_end_cond ();
finish_compound_stmt (/*has_no_scope=*/1, compound_stmt);
finish_then_clause (if_stmt);
finish_if_stmt ();
expand_cleanup_for_base (vbases, flag);
}
/* Undo the call to push_momentary above. */
pop_momentary ();
}
/* Find the context in which this FIELD can be initialized. */
......@@ -1035,6 +998,39 @@ expand_member_init (exp, name, init)
}
}
/* We are about to generate some complex initialization code.
Conceptually, it is all a single expression. However, we may want
to include conditionals, loops, and other such statement-level
constructs. Therefore, we build the initialization code inside a
statement-expression. This function starts such an expression.
STMT_EXPR_P and COMPOUND_STMT_P are filled in by this function;
pass them back to finish_init_stmts when the expression is
complete. */
static void
begin_init_stmts (stmt_expr_p, compound_stmt_p)
tree *stmt_expr_p;
tree *compound_stmt_p;
{
push_momentary ();
*stmt_expr_p = begin_stmt_expr ();
*compound_stmt_p = begin_compound_stmt (/*has_no_scope=*/1);
}
/* Finish out the statement-expression begun by the previous call to
begin_init_stmts. Returns the statement-expression itself. */
static tree
finish_init_stmts (stmt_expr, compound_stmt)
tree stmt_expr;
tree compound_stmt;
{
pop_momentary ();
return finish_stmt_expr (stmt_expr,
finish_compound_stmt (/*has_no_scope=*/1,
compound_stmt));
}
/* This is like `expand_member_init', only it stores one aggregate
value into another.
......@@ -1073,17 +1069,20 @@ expand_member_init (exp, name, init)
A constructor or a conversion operator may have to be used to
perform the initialization, but not both, as it would be ambiguous. */
void
expand_aggr_init (exp, init, flags)
tree
build_aggr_init (exp, init, flags)
tree exp, init;
int flags;
{
tree stmt_expr;
tree compound_stmt;
int destroy_temps;
tree type = TREE_TYPE (exp);
int was_const = TREE_READONLY (exp);
int was_volatile = TREE_THIS_VOLATILE (exp);
if (init == error_mark_node)
return;
return error_mark_node;
TREE_READONLY (exp) = 0;
TREE_THIS_VOLATILE (exp) = 0;
......@@ -1117,9 +1116,9 @@ expand_aggr_init (exp, init, flags)
}
*/
error ("bad array initializer");
return;
return error_mark_node;
}
expand_vec_init (exp, exp, array_type_nelts (type), init,
stmt_expr = build_vec_init (exp, exp, array_type_nelts (type), init,
init && same_type_p (TREE_TYPE (init),
TREE_TYPE (exp)));
TREE_READONLY (exp) = was_const;
......@@ -1127,28 +1126,26 @@ expand_aggr_init (exp, init, flags)
TREE_TYPE (exp) = type;
if (init)
TREE_TYPE (init) = itype;
return;
return stmt_expr;
}
if (TREE_CODE (exp) == VAR_DECL || TREE_CODE (exp) == PARM_DECL)
/* just know that we've seen something for this node */
TREE_USED (exp) = 1;
#if 0
/* If initializing from a GNU C CONSTRUCTOR, consider the elts in the
constructor as parameters to an implicit GNU C++ constructor. */
if (init && TREE_CODE (init) == CONSTRUCTOR
&& TYPE_HAS_CONSTRUCTOR (type)
&& TREE_TYPE (init) == type)
init = CONSTRUCTOR_ELTS (init);
#endif
TREE_TYPE (exp) = TYPE_MAIN_VARIANT (type);
begin_init_stmts (&stmt_expr, &compound_stmt);
destroy_temps = stmts_are_full_exprs_p;
stmts_are_full_exprs_p = 0;
expand_aggr_init_1 (TYPE_BINFO (type), exp, exp,
init, LOOKUP_NORMAL|flags);
stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
stmts_are_full_exprs_p = destroy_temps;
TREE_TYPE (exp) = type;
TREE_READONLY (exp) = was_const;
TREE_THIS_VOLATILE (exp) = was_volatile;
return stmt_expr;
}
static void
......@@ -1199,7 +1196,7 @@ expand_default_init (binfo, true_exp, exp, init, flags)
else
init = build (INIT_EXPR, TREE_TYPE (exp), exp, init);
TREE_SIDE_EFFECTS (init) = 1;
expand_expr_stmt (init);
finish_expr_stmt (init);
return;
}
......@@ -1225,7 +1222,7 @@ expand_default_init (binfo, true_exp, exp, init, flags)
rval = build_method_call (exp, ctor_identifier,
parms, binfo, flags);
if (TREE_SIDE_EFFECTS (rval))
expand_expr_stmt (rval);
finish_expr_stmt (rval);
}
/* This function is responsible for initializing EXP with INIT
......@@ -1271,15 +1268,20 @@ expand_aggr_init_1 (binfo, true_exp, exp, init, flags)
&& TREE_CODE (init) == CONSTRUCTOR
&& TREE_HAS_CONSTRUCTOR (init))
{
tree t = store_init_value (exp, init);
if (!t)
/* If store_init_value returns NULL_TREE, the INIT has been
record in the DECL_INITIAL for EXP. That means there's
nothing more we have to do. */
if (!store_init_value (exp, init))
{
if (!building_stmt_tree ())
expand_decl_init (exp);
return;
}
t = build (INIT_EXPR, type, exp, init);
else
{
tree t = build (INIT_EXPR, type, exp, init);
TREE_SIDE_EFFECTS (t) = 1;
expand_expr_stmt (t);
finish_expr_stmt (t);
}
return;
}
......@@ -2689,88 +2691,54 @@ build_vec_delete_1 (base, maxindex, type, auto_delete_vec, auto_delete,
return cp_convert (void_type_node, body);
}
/* Protect the vector initialization with a try-block so that we can
destroy the first few elements if constructing a later element
causes an exception to be thrown. TYPE is the type of the array
elements. */
static void
expand_vec_init_try_block (type)
tree
create_temporary_var (type)
tree type;
{
if (!TYPE_NEEDS_DESTRUCTOR (type) || !flag_exceptions)
return;
/* The code we generate looks like:
tree decl;
try {
// Initialize the vector.
} catch (...) {
// Destory the elements that need destroying.
throw;
}
decl = build_decl (VAR_DECL, NULL_TREE, type);
TREE_USED (decl) = 1;
DECL_ARTIFICIAL (decl) = 1;
DECL_SOURCE_FILE (decl) = input_filename;
DECL_SOURCE_LINE (decl) = lineno;
DECL_IGNORED_P (decl) = 1;
Here we're just beginning the `try'. */
if (building_stmt_tree ())
add_decl_stmt (decl);
else
DECL_RTL (decl) = assign_temp (type, 2, 0, 1);
expand_eh_region_start ();
return decl;
}
/* Add code to destroy the array elements constructed so far if the
construction of some element in the array causes an exception to be
thrown. RVAL is the address of the last element in the array.
TYPE is the type of the array elements. MAXINDEX is the maximum
allowable index into the array. ITERATOR is an integer variable
indicating how many elements remain to be constructed. */
static void
expand_vec_init_catch_clause (rval, type, maxindex, iterator)
tree rval;
tree type;
tree maxindex;
tree iterator;
{
tree e;
tree cleanup;
if (!TYPE_NEEDS_DESTRUCTOR (type) || !flag_exceptions)
return;
/* Create a new temporary variable of the indicated TYPE, initialized
to INIT.
/* We have to ensure that this can live to the cleanup expansion
time, since we know it is only ever needed once, generate code
now. */
push_obstacks_nochange ();
resume_temporary_allocation ();
It is not entered into current_binding_level, because that breaks
things when it comes time to do final cleanups (which take place
"outside" the binding contour of the function). */
cleanup = make_node (RTL_EXPR);
TREE_TYPE (cleanup) = void_type_node;
RTL_EXPR_RTL (cleanup) = const0_rtx;
TREE_SIDE_EFFECTS (cleanup) = 1;
do_pending_stack_adjust ();
start_sequence_for_rtl_expr (cleanup);
static tree
get_temp_regvar (type, init)
tree type, init;
{
tree decl;
e = build_vec_delete_1 (rval,
build_binary_op (MINUS_EXPR, maxindex,
iterator),
type,
/*auto_delete_vec=*/integer_zero_node,
/*auto_delete=*/integer_zero_node,
/*use_global_delete=*/0);
expand_expr (e, const0_rtx, VOIDmode, EXPAND_NORMAL);
decl = create_temporary_var (type);
DECL_REGISTER (decl) = 1;
finish_expr_stmt (build_modify_expr (decl, INIT_EXPR, init));
do_pending_stack_adjust ();
RTL_EXPR_SEQUENCE (cleanup) = get_insns ();
end_sequence ();
cleanup = protect_with_terminate (cleanup);
expand_eh_region_end (cleanup);
pop_obstacks ();
return decl;
}
/* `expand_vec_init' performs initialization of a vector of aggregate
types.
/* `build_vec_init' returns tree structure that performs
initialization of a vector of aggregate types.
DECL is passed only for error reporting, and provides line number
and source file name information.
BASE is the space where the vector will be.
BASE is the space where the vector will be. For a vector of Ts,
the type of BASE is `T*'.
MAXINDEX is the maximum index of the array (one less than the
number of elements).
INIT is the (possibly NULL) initializer.
......@@ -2783,16 +2751,23 @@ expand_vec_init_catch_clause (rval, type, maxindex, iterator)
but use assignment instead of initialization. */
tree
expand_vec_init (decl, base, maxindex, init, from_array)
build_vec_init (decl, base, maxindex, init, from_array)
tree decl, base, maxindex, init;
int from_array;
{
tree rval;
tree base2 = NULL_TREE;
tree type = TREE_TYPE (TREE_TYPE (base));
tree size;
tree itype = NULL_TREE;
tree iterator;
/* The type of an element in the array. */
tree type;
/* The type of a pointer to an element in the array. */
tree ptype;
tree stmt_expr;
tree compound_stmt;
int destroy_temps;
tree try_block;
int num_initialized_elts = 0;
maxindex = cp_convert (ptrdiff_type_node, maxindex);
......@@ -2808,17 +2783,56 @@ expand_vec_init (decl, base, maxindex, init, from_array)
return rval;
}
type = TREE_TYPE (TREE_TYPE (base));
ptype = build_pointer_type (type);
size = size_in_bytes (type);
base = default_conversion (base);
base = cp_convert (build_pointer_type (type), base);
rval = get_temp_regvar (build_pointer_type (type), base);
base = get_temp_regvar (build_pointer_type (type), base);
/* The code we are generating looks like:
T* t1 = (T*) base;
T* rval = base;
ptrdiff_t iterator = maxindex;
try {
... initializations from CONSTRUCTOR ...
if (iterator != -1) {
do {
... initialize *base ...
++base;
} while (--iterator != -1);
}
} catch (...) {
... destroy elements that were constructed ...
}
We can omit the try and catch blocks if we know that the
initialization will never throw an exception, or if the array
elements do not have destructors. If we have a CONSTRUCTOR to
give us initialization information, we emit code to initialize
each of the elements before the loop in the try block, and then
iterate over fewer elements. We can omit the loop completely if
the elements of the array do not have constructors.
We actually wrap the entire body of the above in a STMT_EXPR, for
tidiness.
When copying from array to another, when the array elements have
only trivial copy constructors, we should use __builtin_memcpy
rather than generating a loop. That way, we could take advantage
of whatever cleverness the back-end has for dealing with copies
of blocks of memory. */
begin_init_stmts (&stmt_expr, &compound_stmt);
destroy_temps = stmts_are_full_exprs_p;
stmts_are_full_exprs_p = 0;
rval = get_temp_regvar (ptype,
cp_convert (ptype, default_conversion (base)));
base = get_temp_regvar (ptype, rval);
iterator = get_temp_regvar (ptrdiff_type_node, maxindex);
/* Protect the entire array initialization so that we can destroy
the partially constructed array if an exception is thrown. */
expand_vec_init_try_block (type);
if (flag_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
try_block = begin_try_block ();
if (init != NULL_TREE && TREE_CODE (init) == CONSTRUCTOR
&& (!decl || same_type_p (TREE_TYPE (init), TREE_TYPE (decl))))
......@@ -2827,35 +2841,37 @@ expand_vec_init (decl, base, maxindex, init, from_array)
initializers. */
tree elts;
tree baseref = build1 (INDIRECT_REF, type, base);
from_array = 0;
for (elts = CONSTRUCTOR_ELTS (init); elts; elts = TREE_CHAIN (elts))
{
tree elt = TREE_VALUE (elts);
tree baseref = build1 (INDIRECT_REF, type, base);
num_initialized_elts++;
if (IS_AGGR_TYPE (type) || TREE_CODE (type) == ARRAY_TYPE)
expand_aggr_init (baseref, elt, 0);
finish_expr_stmt (build_aggr_init (baseref, elt, 0));
else
expand_assignment (baseref, elt, 0, 0);
finish_expr_stmt (build_modify_expr (baseref, NOP_EXPR,
elt));
expand_assignment (base,
finish_expr_stmt (build_modify_expr
(base,
NOP_EXPR,
build (PLUS_EXPR, build_pointer_type (type),
base, size),
0, 0);
expand_assignment (iterator,
base, size)));
finish_expr_stmt (build_modify_expr
(iterator,
NOP_EXPR,
build (MINUS_EXPR, ptrdiff_type_node,
iterator, integer_one_node),
0, 0);
iterator, integer_one_node)));
}
/* Clear out INIT so that we don't get confused below. */
init = NULL_TREE;
if (obey_regdecls)
if (obey_regdecls && !building_stmt_tree ())
use_variable (DECL_RTL (base));
}
else if (from_array)
......@@ -2897,14 +2913,32 @@ expand_vec_init (decl, base, maxindex, init, from_array)
{
/* If the ITERATOR is equal to -1, then we don't have to loop;
we've already initialized all the elements. */
expand_start_cond (build (NE_EXPR, boolean_type_node,
tree if_stmt;
tree do_stmt;
tree do_body;
tree elt_init;
if_stmt = begin_if_stmt ();
finish_if_stmt_cond (build (NE_EXPR, boolean_type_node,
iterator, minus_one),
0);
if_stmt);
/* Otherwise, loop through the elements. */
expand_start_loop_continue_elsewhere (1);
/* The initialization of each array element is a full-expression. */
do_stmt = begin_do_stmt ();
do_body = begin_compound_stmt (/*has_no_scope=*/1);
/* When we're not building a statement-tree, things are a little
complicated. If, when we recursively call build_aggr_init,
an expression containing a TARGET_EXPR is expanded, then it
may get a cleanup. Then, the result of that expression is
passed to finish_expr_stmt, which will call
expand_start_target_temps/expand_end_target_temps. However,
the latter call will not cause the cleanup to run because
that block will still be on the block stack. So, we call
expand_start_target_temps here manually; the corresponding
call to expand_end_target_temps below will cause the cleanup
to be performed. */
if (!building_stmt_tree ())
expand_start_target_temps ();
if (from_array)
......@@ -2918,11 +2952,11 @@ expand_vec_init (decl, base, maxindex, init, from_array)
from = NULL_TREE;
if (from_array == 2)
expand_expr_stmt (build_modify_expr (to, NOP_EXPR, from));
elt_init = build_modify_expr (to, NOP_EXPR, from);
else if (TYPE_NEEDS_CONSTRUCTING (type))
expand_aggr_init (to, from, 0);
elt_init = build_aggr_init (to, from, 0);
else if (from)
expand_assignment (to, from, 0, 0);
elt_init = build_modify_expr (to, NOP_EXPR, from);
else
my_friendly_abort (57);
}
......@@ -2930,56 +2964,100 @@ expand_vec_init (decl, base, maxindex, init, from_array)
{
if (init != 0)
sorry ("cannot initialize multi-dimensional array with initializer");
expand_vec_init (decl,
elt_init = (build_vec_init
(decl,
build1 (NOP_EXPR,
build_pointer_type (TREE_TYPE
(type)),
build_pointer_type (TREE_TYPE (type)),
base),
array_type_nelts (type), 0, 0);
array_type_nelts (type), 0, 0));
}
else
elt_init = build_aggr_init (build1 (INDIRECT_REF, type, base),
init, 0);
/* The initialization of each array element is a
full-expression. */
if (!building_stmt_tree ())
{
finish_expr_stmt (elt_init);
expand_end_target_temps ();
}
else
expand_aggr_init (build1 (INDIRECT_REF, type, base), init, 0);
{
stmts_are_full_exprs_p = 1;
finish_expr_stmt (elt_init);
stmts_are_full_exprs_p = 0;
}
expand_assignment (base,
finish_expr_stmt (build_modify_expr
(base,
NOP_EXPR,
build (PLUS_EXPR, build_pointer_type (type),
base, size), 0, 0);
base, size)));
if (base2)
expand_assignment (base2,
finish_expr_stmt (build_modify_expr
(base2,
NOP_EXPR,
build (PLUS_EXPR, build_pointer_type (type),
base2, size), 0, 0);
/* Cleanup any temporaries needed for the initial value. */
expand_end_target_temps ();
expand_loop_continue_here ();
expand_exit_loop_if_false (0, build (NE_EXPR, boolean_type_node,
build (PREDECREMENT_EXPR,
ptrdiff_type_node,
iterator,
integer_one_node),
minus_one));
base2, size)));
if (obey_regdecls)
if (obey_regdecls && !building_stmt_tree ())
{
use_variable (DECL_RTL (base));
if (base2)
use_variable (DECL_RTL (base2));
}
expand_end_loop ();
expand_end_cond ();
finish_compound_stmt (/*has_no_scope=*/1, do_body);
finish_do_body (do_stmt);
finish_do_stmt (build (NE_EXPR, boolean_type_node,
build (PREDECREMENT_EXPR,
ptrdiff_type_node,
iterator,
integer_one_node),
minus_one),
do_stmt);
finish_then_clause (if_stmt);
finish_if_stmt ();
}
/* Make sure to cleanup any partially constructed elements. */
expand_vec_init_catch_clause (rval, type, maxindex, iterator);
if (flag_exceptions && TYPE_NEEDS_DESTRUCTOR (type))
{
tree e;
/* Because CLEANUP will not be processed until later, it must go
on the temporary obstack. */
push_obstacks_nochange ();
resume_temporary_allocation ();
/* And MAXINDEX needs to be copied to the current obstack. It's
probably on the momentary obstack now. */
maxindex = mapcar (maxindex, permanent_p);
e = build_vec_delete_1 (rval,
build_binary_op (MINUS_EXPR, maxindex,
iterator),
type,
/*auto_delete_vec=*/integer_zero_node,
/*auto_delete=*/integer_zero_node,
/*use_global_delete=*/0);
pop_obstacks ();
finish_cleanup (e, try_block);
}
if (obey_regdecls)
if (obey_regdecls && !building_stmt_tree ())
{
use_variable (DECL_RTL (iterator));
use_variable (DECL_RTL (rval));
}
return rval;
/* The value of the array initialization is the address of the
first element in the array. */
finish_expr_stmt (rval);
stmt_expr = finish_init_stmts (stmt_expr, compound_stmt);
stmts_are_full_exprs_p = destroy_temps;
return stmt_expr;
}
/* Free up storage of type TYPE, at address ADDR.
......
......@@ -2177,11 +2177,9 @@ do_build_copy_constructor (fndecl)
tree fndecl;
{
tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
tree compound_stmt;
tree t;
clear_last_expr ();
push_momentary ();
if (TYPE_USES_VIRTUAL_BASECLASSES (current_class_type))
parm = TREE_CHAIN (parm);
parm = convert_from_reference (parm);
......@@ -2194,7 +2192,7 @@ do_build_copy_constructor (fndecl)
{
t = build (INIT_EXPR, void_type_node, current_class_ref, parm);
TREE_SIDE_EFFECTS (t) = 1;
cplus_expand_expr_stmt (t);
finish_expr_stmt (t);
}
else
{
......@@ -2257,7 +2255,8 @@ do_build_copy_constructor (fndecl)
setup_vtbl_ptr ();
}
pop_momentary ();
compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
}
static void
......@@ -2265,10 +2264,9 @@ do_build_assign_ref (fndecl)
tree fndecl;
{
tree parm = TREE_CHAIN (DECL_ARGUMENTS (fndecl));
tree compound_stmt;
clear_last_expr ();
push_momentary ();
compound_stmt = begin_compound_stmt (/*has_no_scope=*/0);
parm = convert_from_reference (parm);
if (TYPE_HAS_TRIVIAL_ASSIGN_REF (current_class_type)
......@@ -2279,7 +2277,7 @@ do_build_assign_ref (fndecl)
{
tree t = build (MODIFY_EXPR, void_type_node, current_class_ref, parm);
TREE_SIDE_EFFECTS (t) = 1;
cplus_expand_expr_stmt (t);
finish_expr_stmt (t);
}
else
{
......@@ -2353,7 +2351,7 @@ do_build_assign_ref (fndecl)
}
}
c_expand_return (current_class_ref);
pop_momentary ();
finish_compound_stmt (/*has_no_scope=*/0, compound_stmt);
}
void
......@@ -2374,6 +2372,7 @@ synthesize_method (fndecl)
interface_unknown = 1;
start_function (NULL_TREE, fndecl, NULL_TREE, 1);
store_parm_decls ();
clear_last_expr ();
if (DECL_NAME (fndecl) == ansi_opname[MODIFY_EXPR])
do_build_assign_ref (fndecl);
......
This source diff could not be displayed because it is too large. You can view the blob instead.
typedef union {long itype; tree ttype; char *strtype; enum tree_code code; flagged_type_tree ftype; } YYSTYPE;
#define IDENTIFIER 258
#define TYPENAME 259
#define SELFNAME 260
#define PFUNCNAME 261
#define SCSPEC 262
#define TYPESPEC 263
#define CV_QUALIFIER 264
#define CONSTANT 265
#define STRING 266
#define ELLIPSIS 267
#define SIZEOF 268
#define ENUM 269
#define IF 270
#define ELSE 271
#define WHILE 272
#define DO 273
#define FOR 274
#define SWITCH 275
#define CASE 276
#define DEFAULT 277
#define BREAK 278
#define CONTINUE 279
#define RETURN_KEYWORD 280
#define GOTO 281
#define ASM_KEYWORD 282
#define TYPEOF 283
#define ALIGNOF 284
#define SIGOF 285
#define ATTRIBUTE 286
#define EXTENSION 287
#define LABEL 288
#define REALPART 289
#define IMAGPART 290
#define VA_ARG 291
#define AGGR 292
#define VISSPEC 293
#define DELETE 294
#define NEW 295
#define THIS 296
#define OPERATOR 297
#define CXX_TRUE 298
#define CXX_FALSE 299
#define NAMESPACE 300
#define TYPENAME_KEYWORD 301
#define USING 302
#define LEFT_RIGHT 303
#define TEMPLATE 304
#define TYPEID 305
#define DYNAMIC_CAST 306
#define STATIC_CAST 307
#define REINTERPRET_CAST 308
#define CONST_CAST 309
#define SCOPE 310
#define EMPTY 311
#define PTYPENAME 312
#define NSNAME 313
#define THROW 314
#define ASSIGN 315
#define OROR 316
#define ANDAND 317
#define MIN_MAX 318
#define EQCOMPARE 319
#define ARITHCOMPARE 320
#define LSHIFT 321
#define RSHIFT 322
#define POINTSAT_STAR 323
#define DOT_STAR 324
#define UNARY 325
#define PLUSPLUS 326
#define MINUSMINUS 327
#define HYPERUNARY 328
#define POINTSAT 329
#define TRY 330
#define CATCH 331
#define PRE_PARSED_FUNCTION_DECL 332
#define EXTERN_LANG_STRING 333
#define ALL 334
#define PRE_PARSED_CLASS_DECL 335
#define DEFARG 336
#define DEFARG_MARKER 337
#define TYPENAME_DEFN 338
#define IDENTIFIER_DEFN 339
#define PTYPENAME_DEFN 340
#define END_OF_LINE 341
#define END_OF_SAVED_INPUT 342
#define IDENTIFIER 257
#define TYPENAME 258
#define SELFNAME 259
#define PFUNCNAME 260
#define SCSPEC 261
#define TYPESPEC 262
#define CV_QUALIFIER 263
#define CONSTANT 264
#define STRING 265
#define ELLIPSIS 266
#define SIZEOF 267
#define ENUM 268
#define IF 269
#define ELSE 270
#define WHILE 271
#define DO 272
#define FOR 273
#define SWITCH 274
#define CASE 275
#define DEFAULT 276
#define BREAK 277
#define CONTINUE 278
#define RETURN_KEYWORD 279
#define GOTO 280
#define ASM_KEYWORD 281
#define TYPEOF 282
#define ALIGNOF 283
#define SIGOF 284
#define ATTRIBUTE 285
#define EXTENSION 286
#define LABEL 287
#define REALPART 288
#define IMAGPART 289
#define VA_ARG 290
#define AGGR 291
#define VISSPEC 292
#define DELETE 293
#define NEW 294
#define THIS 295
#define OPERATOR 296
#define CXX_TRUE 297
#define CXX_FALSE 298
#define NAMESPACE 299
#define TYPENAME_KEYWORD 300
#define USING 301
#define LEFT_RIGHT 302
#define TEMPLATE 303
#define TYPEID 304
#define DYNAMIC_CAST 305
#define STATIC_CAST 306
#define REINTERPRET_CAST 307
#define CONST_CAST 308
#define SCOPE 309
#define EMPTY 310
#define PTYPENAME 311
#define NSNAME 312
#define THROW 313
#define ASSIGN 314
#define OROR 315
#define ANDAND 316
#define MIN_MAX 317
#define EQCOMPARE 318
#define ARITHCOMPARE 319
#define LSHIFT 320
#define RSHIFT 321
#define POINTSAT_STAR 322
#define DOT_STAR 323
#define UNARY 324
#define PLUSPLUS 325
#define MINUSMINUS 326
#define HYPERUNARY 327
#define POINTSAT 328
#define TRY 329
#define CATCH 330
#define PRE_PARSED_FUNCTION_DECL 331
#define EXTERN_LANG_STRING 332
#define ALL 333
#define PRE_PARSED_CLASS_DECL 334
#define DEFARG 335
#define DEFARG_MARKER 336
#define TYPENAME_DEFN 337
#define IDENTIFIER_DEFN 338
#define PTYPENAME_DEFN 339
#define END_OF_LINE 340
#define END_OF_SAVED_INPUT 341
extern YYSTYPE yylval;
......
......@@ -780,10 +780,6 @@ base_init:
if ($3 == 0)
error ("no base initializers given following ':'");
setup_vtbl_ptr ();
/* Always keep the BLOCK node associated with the outermost
pair of curley braces of a function. These are needed
for correct operation of dwarfout.c. */
keep_next_level ();
}
;
......@@ -1623,10 +1619,6 @@ nodecls:
if (! current_function_parms_stored)
store_parm_decls ();
setup_vtbl_ptr ();
/* Always keep the BLOCK node associated with the outermost
pair of curley braces of a function. These are needed
for correct operation of dwarfout.c. */
keep_next_level ();
}
;
......
......@@ -7424,12 +7424,17 @@ tsubst_expr (t, args, complain, in_decl)
stmt = begin_try_block ();
tsubst_expr (TRY_STMTS (t), args, complain, in_decl);
finish_try_block (stmt);
if (CLEANUP_P (t))
finish_cleanup (tsubst_expr (TRY_HANDLERS (t), args,
complain, in_decl),
stmt);
else
{
tree handler = TRY_HANDLERS (t);
for (; handler; handler = TREE_CHAIN (handler))
tsubst_expr (handler, args, complain, in_decl);
}
finish_handler_sequence (stmt);
}
break;
case HANDLER:
......
......@@ -42,12 +42,27 @@
much easier since it will be able to make use of these routines. */
static void expand_stmts PROTO((tree));
static void do_pushlevel PROTO((void));
static tree do_poplevel PROTO((void));
/* Non-zero if we should generate RTL for functions that we process.
When this is zero, we just accumulate tree structure, without
interacting with the back end. */
int expanding_p = 1;
/* Non-zero if we should treat statements as full expressions. In
particular, this variable is no-zero if at the end of a statement
we should destroy any temporaries created during that statement.
Similarly, if, at the end of a block, we should destroy any local
variables in this block. Normally, this variable is non-zero,
since those are the normal semantics of C++.
However, in order to represent aggregate initialization code as
tree structure, we use statement-expressions. The statements
within the statement expression should not result in cleanups being
run until the entire enclosing statement is complete. */
int stmts_are_full_exprs_p = 1;
/* The type of the last expression-statement we have seen. This is
required because the type of a statement-expression is the type of
the last expression statement. */
......@@ -91,11 +106,19 @@ finish_expr_stmt (expr)
&& lvalue_p (expr))
|| TREE_CODE (TREE_TYPE (expr)) == FUNCTION_TYPE)
expr = default_conversion (expr);
if (stmts_are_full_exprs_p)
expand_start_target_temps ();
cplus_expand_expr_stmt (expr);
}
if (stmts_are_full_exprs_p)
{
expand_end_target_temps ();
clear_momentary ();
}
}
}
finish_stmt ();
......@@ -455,7 +478,7 @@ finish_for_stmt (expr, for_stmt)
emit_line_note (input_filename, lineno);
expand_loop_continue_here ();
if (expr)
cplus_expand_expr_stmt (expr);
finish_expr_stmt (expr);
expand_end_loop ();
}
......@@ -647,6 +670,23 @@ finish_try_block (try_block)
expand_start_all_catch ();
}
/* Finish an implicitly generated try-block, with a cleanup is given
by CLEANUP. */
void
finish_cleanup (cleanup, try_block)
tree cleanup;
tree try_block;
{
if (building_stmt_tree ())
{
TRY_HANDLERS (try_block) = copy_to_permanent (cleanup);
CLEANUP_P (try_block) = 1;
}
else
expand_eh_region_end (protect_with_terminate (cleanup));
}
/* Likewise, for a function-try-block. */
void
......@@ -673,9 +713,7 @@ finish_handler_sequence (try_block)
if (building_stmt_tree ())
RECHAIN_STMTS_FROM_CHAIN (try_block, TRY_HANDLERS (try_block));
else
{
expand_end_all_catch ();
}
}
/* Likewise, for a function-try-block. */
......@@ -762,6 +800,12 @@ begin_compound_stmt (has_no_scope)
if (!has_no_scope)
do_pushlevel ();
else
/* Normally, we try hard to keep the BLOCK for a
statement-expression. But, if it's a statement-expression with
a scopeless block, there's nothing to keep, and we don't want
to accidentally keep a block *inside* the scopeless block. */
keep_next_level (0);
return r;
}
......@@ -904,6 +948,23 @@ add_decl_stmt (decl)
add_tree (decl_stmt);
}
/* We're in a constructor, and have just constructed a a subobject of
*THIS. CLEANUP is code to run if an exception is thrown before the
end of the current function is reached. */
void
finish_subobject (cleanup)
tree cleanup;
{
if (building_stmt_tree ())
{
tree r = build_min_nt (SUBOBJECT, cleanup);
add_tree (r);
}
else
add_partial_entry (cleanup);
}
/* Bind a name and initialization to the return value of
the current function. */
......@@ -975,13 +1036,18 @@ setup_vtbl_ptr ()
(CTOR_INITIALIZER,
current_member_init_list, current_base_init_list));
else
emit_base_init (current_class_type, 0);
emit_base_init (current_class_type);
}
/* Always keep the BLOCK node associated with the outermost pair of
curley braces of a function. These are needed for correct
operation of dwarfout.c. */
keep_next_level (1);
}
/* Begin a new scope. */
void
static void
do_pushlevel ()
{
if (!building_stmt_tree ())
......@@ -989,21 +1055,23 @@ do_pushlevel ()
emit_line_note (input_filename, lineno);
clear_last_expr ();
}
pushlevel (0);
push_momentary ();
if (!building_stmt_tree ())
if (stmts_are_full_exprs_p)
pushlevel (0);
if (!building_stmt_tree () && stmts_are_full_exprs_p)
expand_start_bindings (0);
}
/* Finish a scope. */
tree
static tree
do_poplevel ()
{
tree t;
if (!building_stmt_tree ())
if (!building_stmt_tree () && stmts_are_full_exprs_p)
expand_end_bindings (getdecls (), kept_level_p (), 0);
if (stmts_are_full_exprs_p)
t = poplevel (kept_level_p (), 1, 0);
pop_momentary ();
return t;
......@@ -1028,7 +1096,7 @@ finish_parenthesized_expr (expr)
tree
begin_stmt_expr ()
{
keep_next_level ();
keep_next_level (1);
/* If we're building a statement tree, then the upcoming compound
statement will be chained onto the tree structure, starting at
last_tree. We return last_tree so that we can later unhook the
......@@ -1055,9 +1123,6 @@ finish_stmt_expr (rtl_expr, expr)
TREE_SIDE_EFFECTS (rtl_expr) = 1;
}
if (TREE_CODE (expr) == BLOCK)
{
/* Make a BIND_EXPR for the BLOCK already made. */
if (building_stmt_tree ())
{
/* If the last thing in the statement-expression was not an
......@@ -1065,28 +1130,27 @@ finish_stmt_expr (rtl_expr, expr)
if (!last_expr_type)
last_expr_type = void_type_node;
result = build_min (STMT_EXPR, last_expr_type, last_tree);
/* FIXME: Do we need this? */
TREE_SIDE_EFFECTS (result) = 1;
/* Remove the compound statement from the tree structure; it is
now saved in the STMT_EXPR. */
last_tree = rtl_expr;
TREE_CHAIN (last_tree) = NULL_TREE;
}
else
else if (expr && TREE_CODE (expr) == BLOCK)
{
result = build (BIND_EXPR, TREE_TYPE (rtl_expr),
NULL_TREE, rtl_expr, expr);
/* Remove the block from the tree at this point. It gets put
back at the proper place when the STMT_EXPR or BIND_EXPR is
expanded. */
delete_block (expr);
}
else
result = expr;
result = rtl_expr;
if (building_stmt_tree ())
{
/* Remove the compound statement from the tree structure; it is
now saved in the STMT_EXPR. */
last_tree = rtl_expr;
TREE_CHAIN (last_tree) = NULL_TREE;
}
if (expr && TREE_CODE (expr) == BLOCK)
/* Remove the block from the tree at this point. It gets put back
at the proper place when the STMT_EXPR or BIND_EXPR is
expanded. */
delete_block (expr);
return result;
}
......@@ -2082,11 +2146,20 @@ expand_stmt (t)
case TRY_BLOCK:
lineno = STMT_LINENO (t);
if (CLEANUP_P (t))
{
expand_eh_region_start ();
expand_stmt (TRY_STMTS (t));
finish_cleanup (TRY_HANDLERS (t), NULL_TREE);
}
else
{
begin_try_block ();
expand_stmt (TRY_STMTS (t));
finish_try_block (NULL_TREE);
expand_stmts (TRY_HANDLERS (t));
finish_handler_sequence (NULL_TREE);
}
break;
case HANDLER:
......@@ -2105,6 +2178,11 @@ expand_stmt (t)
finish_handler (NULL_TREE);
break;
case SUBOBJECT:
lineno = STMT_LINENO (t);
finish_subobject (SUBOBJECT_CLEANUP (t));
break;
default:
my_friendly_abort (19990810);
break;
......@@ -2168,11 +2246,6 @@ expand_body (fn)
base-classes. */
setup_vtbl_ptr ();
/* Always keep the BLOCK node associated with the outermost pair of
curly braces of a function. These are needed for correct
operation of dwarfout.c. */
keep_next_level ();
/* Expand the body. */
expand_stmt (t);
......
......@@ -1656,6 +1656,7 @@ search_tree (t, func)
case CALL_EXPR:
case COMPOUND_EXPR:
case MODIFY_EXPR:
case INIT_EXPR:
TRY (TREE_OPERAND (t, 0));
TRY (TREE_OPERAND (t, 1));
break;
......@@ -1920,6 +1921,7 @@ mapcar (t, func)
case WITH_CLEANUP_EXPR:
case COMPOUND_EXPR:
case MODIFY_EXPR:
case INIT_EXPR:
t = copy_node (t);
TREE_OPERAND (t, 0) = mapcar (TREE_OPERAND (t, 0), func);
TREE_OPERAND (t, 1) = mapcar (TREE_OPERAND (t, 1), func);
......
......@@ -5989,32 +5989,11 @@ build_modify_expr (lhs, modifycode, rhs)
if (pedantic && ! DECL_ARTIFICIAL (current_function_decl))
pedwarn ("ANSI C++ forbids assignment of arrays");
/* Have to wrap this in RTL_EXPR for two cases:
in base or member initialization and if we
are a branch of a ?: operator. Since we
can't easily know the latter, just do it always. */
result = make_node (RTL_EXPR);
TREE_TYPE (result) = void_type_node;
do_pending_stack_adjust ();
start_sequence_for_rtl_expr (result);
/* As a matter of principle, `start_sequence' should do this. */
emit_note (0, -1);
from_array = TREE_CODE (TREE_TYPE (newrhs)) == ARRAY_TYPE
? 1 + (modifycode != INIT_EXPR): 0;
expand_vec_init (lhs, lhs, array_type_nelts (lhstype), newrhs,
from_array);
do_pending_stack_adjust ();
TREE_SIDE_EFFECTS (result) = 1;
RTL_EXPR_SEQUENCE (result) = get_insns ();
RTL_EXPR_RTL (result) = const0_rtx;
end_sequence ();
return result;
return (build_vec_init
(lhs, lhs, array_type_nelts (lhstype), newrhs,
from_array));
}
if (modifycode == INIT_EXPR)
......
......@@ -465,7 +465,7 @@ store_init_value (decl, init)
;
/* Other code expects that initializers for objects of types that need
constructing never make it into DECL_INITIAL, and passes 'init' to
expand_aggr_init without checking DECL_INITIAL. So just return. */
build_aggr_init without checking DECL_INITIAL. So just return. */
else if (TYPE_NEEDS_CONSTRUCTING (type))
return value;
else if (TREE_STATIC (decl)
......
// Build don't link:
// Special g++ Options: -fno-const-strings
// Origin: Mark Mitchell <mark@codesourcery.com>
char foo[26];
template <class T>
void f ()
{
foo = "0123456789012345678901234";
}
template void f<int>();
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment