aboutsummaryrefslogtreecommitdiff
path: root/gcc/cp/decl.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/cp/decl.c')
-rw-r--r--gcc/cp/decl.c109
1 files changed, 76 insertions, 33 deletions
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 469e6b8..d653fc4 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -5136,6 +5136,41 @@ make_rtl_for_nonlocal_decl (tree decl, tree init, const char* asmspec)
rest_of_decl_compilation (decl, toplev, at_eof);
}
+/* walk_tree helper for wrap_temporary_cleanups, below. */
+
+static tree
+wrap_cleanups_r (tree *stmt_p, int *walk_subtrees, void *data)
+{
+ if (TYPE_P (*stmt_p))
+ {
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
+
+ if (TREE_CODE (*stmt_p) == TARGET_EXPR)
+ {
+ tree guard = (tree)data;
+ tree tcleanup = TARGET_EXPR_CLEANUP (*stmt_p);
+
+ tcleanup = build2 (TRY_CATCH_EXPR, void_type_node, tcleanup, guard);
+
+ TARGET_EXPR_CLEANUP (*stmt_p) = tcleanup;
+ }
+
+ return NULL_TREE;
+}
+
+/* We're initializing a local variable which has a cleanup GUARD. If there
+ are any temporaries used in the initializer INIT of this variable, we
+ need to wrap their cleanups with TRY_CATCH_EXPR (, GUARD) so that the
+ variable will be cleaned up properly if one of them throws. */
+
+static void
+wrap_temporary_cleanups (tree init, tree guard)
+{
+ cp_walk_tree_without_duplicates (&init, wrap_cleanups_r, (void *)guard);
+}
+
/* Generate code to initialize DECL (a local variable). */
static void
@@ -5143,6 +5178,7 @@ initialize_local_var (tree decl, tree init)
{
tree type = TREE_TYPE (decl);
tree cleanup;
+ int already_used;
gcc_assert (TREE_CODE (decl) == VAR_DECL
|| TREE_CODE (decl) == RESULT_DECL);
@@ -5153,46 +5189,53 @@ initialize_local_var (tree decl, tree init)
/* If we used it already as memory, it must stay in memory. */
DECL_INITIAL (decl) = NULL_TREE;
TREE_ADDRESSABLE (decl) = TREE_USED (decl);
+ return;
}
- if (DECL_SIZE (decl) && type != error_mark_node)
- {
- int already_used;
+ if (type == error_mark_node)
+ return;
- /* Compute and store the initial value. */
- already_used = TREE_USED (decl) || TREE_USED (type);
+ /* Compute and store the initial value. */
+ already_used = TREE_USED (decl) || TREE_USED (type);
- /* Perform the initialization. */
- if (init)
- {
- int saved_stmts_are_full_exprs_p;
+ /* Generate a cleanup, if necessary. */
+ cleanup = cxx_maybe_build_cleanup (decl);
- gcc_assert (building_stmt_tree ());
- saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
- current_stmt_tree ()->stmts_are_full_exprs_p = 1;
- finish_expr_stmt (init);
- current_stmt_tree ()->stmts_are_full_exprs_p =
- saved_stmts_are_full_exprs_p;
- }
+ /* Perform the initialization. */
+ if (init)
+ {
+ int saved_stmts_are_full_exprs_p;
- /* Set this to 0 so we can tell whether an aggregate which was
- initialized was ever used. Don't do this if it has a
- destructor, so we don't complain about the 'resource
- allocation is initialization' idiom. Now set
- attribute((unused)) on types so decls of that type will be
- marked used. (see TREE_USED, above.) */
- if (TYPE_NEEDS_CONSTRUCTING (type)
- && ! already_used
- && TYPE_HAS_TRIVIAL_DESTRUCTOR (type)
- && DECL_NAME (decl))
- TREE_USED (decl) = 0;
- else if (already_used)
- TREE_USED (decl) = 1;
- }
+ /* If we're only initializing a single object, guard the destructors
+ of any temporaries used in its initializer with its destructor.
+ This isn't right for arrays because each element initialization is
+ a full-expression. */
+ if (cleanup && TREE_CODE (type) != ARRAY_TYPE)
+ wrap_temporary_cleanups (init, cleanup);
- /* Generate a cleanup, if necessary. */
- cleanup = cxx_maybe_build_cleanup (decl);
- if (DECL_SIZE (decl) && cleanup)
+ gcc_assert (building_stmt_tree ());
+ saved_stmts_are_full_exprs_p = stmts_are_full_exprs_p ();
+ current_stmt_tree ()->stmts_are_full_exprs_p = 1;
+ finish_expr_stmt (init);
+ current_stmt_tree ()->stmts_are_full_exprs_p =
+ saved_stmts_are_full_exprs_p;
+ }
+
+ /* Set this to 0 so we can tell whether an aggregate which was
+ initialized was ever used. Don't do this if it has a
+ destructor, so we don't complain about the 'resource
+ allocation is initialization' idiom. Now set
+ attribute((unused)) on types so decls of that type will be
+ marked used. (see TREE_USED, above.) */
+ if (TYPE_NEEDS_CONSTRUCTING (type)
+ && ! already_used
+ && TYPE_HAS_TRIVIAL_DESTRUCTOR (type)
+ && DECL_NAME (decl))
+ TREE_USED (decl) = 0;
+ else if (already_used)
+ TREE_USED (decl) = 1;
+
+ if (cleanup)
finish_decl_cleanup (decl, cleanup);
}