}
/* Convert EXPR to the indicated reference TYPE, in a way suitable for
- initializing a variable of that TYPE. If DECL is non-NULL, it is
+ initializing a variable of that TYPE. If DECL is non-NULL, it is
the VAR_DECL being initialized with the EXPR. (In that case, the
- type of DECL will be TYPE.)
+ type of DECL will be TYPE.) If DECL is non-NULL, then CLEANUP must
+ also be non-NULL, and with *CLEANUP initialized to NULL. Upon
+ return, if *CLEANUP is no longer NULL, it will be a CLEANUP_STMT
+ that should be inserted after the returned expression is used to
+ initialize DECL.
Return the converted expression. */
tree
-initialize_reference (tree type, tree expr, tree decl)
+initialize_reference (tree type, tree expr, tree decl, tree *cleanup)
{
tree conv;
type = TREE_TYPE (expr);
var = make_temporary_var_for_ref_to_temp (decl, type);
layout_decl (var, 0);
+ /* Create the INIT_EXPR that will initialize the temporary
+ variable. */
+ init = build (INIT_EXPR, type, var, expr);
if (at_function_scope_p ())
{
- tree cleanup;
-
add_decl_stmt (var);
- cleanup = cxx_maybe_build_cleanup (var);
- if (cleanup)
- finish_decl_cleanup (var, cleanup);
+ *cleanup = cxx_maybe_build_cleanup (var);
+ if (*cleanup)
+ /* We must be careful to destroy the temporary only
+ after its initialization has taken place. If the
+ initialization throws an exception, then the
+ destructor should not be run. We cannot simply
+ transform INIT into something like:
+
+ (INIT, ({ CLEANUP_STMT; }))
+
+ because emit_local_var always treats the
+ initializer as a full-expression. Thus, the
+ destructor would run too early; it would run at the
+ end of initializing the reference variable, rather
+ than at the end of the block enclosing the
+ reference variable.
+
+ The solution is to pass back a CLEANUP_STMT which
+ the caller is responsible for attaching to the
+ statement tree. */
+ *cleanup = build_stmt (CLEANUP_STMT, var, *cleanup);
}
else
{
static_aggregates = tree_cons (NULL_TREE, var,
static_aggregates);
}
- init = build (INIT_EXPR, type, var, expr);
/* Use its address to initialize the reference variable. */
expr = build_address (var);
expr = build (COMPOUND_EXPR, TREE_TYPE (expr), init, expr);
static tree lookup_tag_reverse (tree, tree);
static void push_local_name (tree);
static void warn_extern_redeclared_static (tree, tree);
-static tree grok_reference_init (tree, tree, tree);
+static tree grok_reference_init (tree, tree, tree, tree *);
static tree grokfndecl (tree, tree, tree, tree, int,
enum overload_flags, tree,
tree, int, int, int, int, int, int, tree);
static void maybe_deduce_size_from_array_init (tree, tree);
static void layout_var_decl (tree);
static void maybe_commonize_var (tree);
-static tree check_initializer (tree, tree, int);
+static tree check_initializer (tree, tree, int, tree *);
static void make_rtl_for_nonlocal_decl (tree, tree, const char *);
static void save_function_data (tree);
static void check_function_type (tree, tree);
if (DECL_ANTICIPATED (olddecl))
; /* Do nothing yet. */
else if ((DECL_EXTERN_C_P (newdecl)
- && DECL_EXTERN_C_P (olddecl))
- || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
- TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
+ && DECL_EXTERN_C_P (olddecl))
+ || compparms (TYPE_ARG_TYPES (TREE_TYPE (newdecl)),
+ TYPE_ARG_TYPES (TREE_TYPE (olddecl))))
{
/* A near match; override the builtin. */
else if (DECL_ANTICIPATED (olddecl))
TREE_TYPE (olddecl) = TREE_TYPE (newdecl);
+ /* Whether or not the builtin can throw exceptions has no
+ bearing on this declarator. */
+ TREE_NOTHROW (olddecl) = 0;
+
if (DECL_THIS_STATIC (newdecl) && !DECL_THIS_STATIC (olddecl))
{
/* If a builtin function is redeclared as `static', merge
DECL_INITIAL (decl) = NULL_TREE;
}
-/* Handle initialization of references.
- These three arguments are from `cp_finish_decl', and have the
- same meaning here that they do there.
+/* Handle initialization of references. DECL, TYPE, and INIT have the
+ same meaning as in cp_finish_decl. *CLEANUP must be NULL on entry,
+ but will be set to a new CLEANUP_STMT if a temporary is created
+ that must be destroeyd subsequently.
+
+ Returns an initializer expression to use to initialize DECL, or
+ NULL if the initialization can be performed statically.
Quotes on semantics can be found in ARM 8.4.3. */
static tree
-grok_reference_init (tree decl, tree type, tree init)
+grok_reference_init (tree decl, tree type, tree init, tree *cleanup)
{
tree tmp;
DECL_INITIAL for local references (instead assigning to them
explicitly); we need to allow the temporary to be initialized
first. */
- tmp = initialize_reference (type, init, decl);
+ tmp = initialize_reference (type, init, decl, cleanup);
if (tmp == error_mark_node)
return NULL_TREE;
}
/* Verify INIT (the initializer for DECL), and record the
- initialization in DECL_INITIAL, if appropriate.
+ initialization in DECL_INITIAL, if appropriate. CLEANUP is as for
+ grok_reference_init.
If the return value is non-NULL, it is an expression that must be
evaluated dynamically to initialize DECL. */
static tree
-check_initializer (tree decl, tree init, int flags)
+check_initializer (tree decl, tree init, int flags, tree *cleanup)
{
tree type = TREE_TYPE (decl);
init = NULL_TREE;
}
else if (!DECL_EXTERNAL (decl) && TREE_CODE (type) == REFERENCE_TYPE)
- init = grok_reference_init (decl, type, init);
+ init = grok_reference_init (decl, type, init, cleanup);
else if (init)
{
if (TREE_CODE (init) == CONSTRUCTOR && TREE_HAS_CONSTRUCTOR (init))
void
cp_finish_decl (tree decl, tree init, tree asmspec_tree, int flags)
{
- register tree type;
+ tree type;
tree ttype = NULL_TREE;
+ tree cleanup;
const char *asmspec = NULL;
int was_readonly = 0;
my_friendly_assert (TREE_CODE (decl) != RESULT_DECL, 20030619);
+ /* Assume no cleanup is required. */
+ cleanup = NULL_TREE;
+
/* If a name was specified, get the string. */
if (global_scope_p (current_binding_level))
asmspec_tree = maybe_apply_renaming_pragma (decl, asmspec_tree);
is *not* defined. */
&& (!DECL_EXTERNAL (decl) || init))
{
- init = check_initializer (decl, init, flags);
+ init = check_initializer (decl, init, flags, &cleanup);
/* Thread-local storage cannot be dynamically initialized. */
if (DECL_THREAD_LOCAL (decl) && init)
{
}
}
+ /* If a CLEANUP_STMT was created to destroy a temporary bound to a
+ reference, insert it in the statement-tree now. */
+ if (cleanup)
+ add_stmt (cleanup);
+
finish_end:
if (was_readonly)