* cp-tree.h (SCOPE_PARTIAL_P): New macro.
(pushlevel_temporary): Remove.
(add_scope_stmt): New function.
* decl.c (pushlevel_temporary): Remove.
(poplevel): Use add_scope_stmt.
(start_decl_1): Likewise.
* semantics.c (add_scope_stmt): New function.
(do_pushlevel): Use it.
(do_poplevel): Use it.
(expand_stmt): Check SCOPE_PARTIAL_P.
From-SVN: r30118
1999-10-21 Mark Mitchell <mark@codesourcery.com>
+ * cp-tree.h (SCOPE_PARTIAL_P): New macro.
+ (pushlevel_temporary): Remove.
+ (add_scope_stmt): New function.
+ * decl.c (pushlevel_temporary): Remove.
+ (poplevel): Use add_scope_stmt.
+ (start_decl_1): Likewise.
+ * semantics.c (add_scope_stmt): New function.
+ (do_pushlevel): Use it.
+ (do_poplevel): Use it.
+ (expand_stmt): Check SCOPE_PARTIAL_P.
+
* cp-tree.def (EMPTY_CLASS_EXPR): New tree node.
* call.c (build_call): Use EMPTY_CLASS_EXPR instead of RTL_EXPR.
* expr.c (cplus_expand_expr): Expand it.
TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
or FIELD_DECL).
NEED_TEMPORARY_P (in REF_BIND, BASE_CONV)
+ SCOPE_PARTIAL_P (in SCOPE_STMT)
5: Not used.
6: Not used.
#define SCOPE_NULLIFIED_P(NODE) \
(TREE_LANG_FLAG_3 (SCOPE_STMT_CHECK (NODE)))
+/* Nonzero for a SCOPE_STMT if this statement is for a partial scope.
+ For example, in:
+
+ S s;
+ l:
+ S s2;
+ goto l;
+
+ there is (implicitly) a new scope after `l', even though there are
+ no curly braces. In particular, when we hit the goto, we must
+ destroy s2 and then re-construct it. For the implicit scope,
+ SCOPE_PARTIAL_P will be set. */
+#define SCOPE_PARTIAL_P(NODE) \
+ (TREE_LANG_FLAG_4 (SCOPE_STMT_CHECK (NODE)))
+
/* Nonzero for an ASM_STMT if the assembly statement is volatile. */
#define ASM_VOLATILE_P(NODE) \
(ASM_CV_QUAL (ASM_STMT_CHECK (NODE)) != NULL_TREE)
extern void set_class_shadows PROTO((tree));
extern void pushlevel PROTO((int));
extern void note_level_for_for PROTO((void));
-extern void pushlevel_temporary PROTO((int));
extern void resume_level PROTO((struct binding_level *));
extern void delete_block PROTO((tree));
extern void insert_block PROTO((tree));
extern void begin_stmt_tree PROTO((tree *));
extern void finish_stmt_tree PROTO((tree *));
extern void prep_stmt PROTO((tree));
+extern void add_scope_stmt PROTO((int, int));
extern void do_pushlevel PROTO((void));
extern tree do_poplevel PROTO((void));
/* Non-zero if we are presently building a statement tree, rather
current_binding_level->is_for_scope = 1;
}
-void
-pushlevel_temporary (tag_transparent)
- int tag_transparent;
-{
- pushlevel (tag_transparent);
- current_binding_level->keep = 2;
- clear_last_expr ();
-
- /* Note we don't call push_momentary() here. Otherwise, it would cause
- cleanups to be allocated on the momentary obstack, and they will be
- overwritten by the next statement. */
-
- expand_start_bindings (0);
-}
-
/* For a binding between a name and an entity at a block scope,
this is the `struct binding_level' for the block. */
#define BINDING_LEVEL(NODE) \
/* Take care of compiler's internal binding structures. */
if (tmp == 2)
{
- expand_end_bindings (getdecls (), keep, 1);
+ add_scope_stmt (/*begin_p=*/0, /*partial_p=*/1);
/* Each and every BLOCK node created here in `poplevel' is important
(e.g. for proper debugging information) so if we created one
earlier, mark it as "used". */
if (block)
TREE_USED (block) = 1;
- block = poplevel (keep, reverse, real_functionbody);
+ block = poplevel (keep, reverse, functionbody);
}
/* Each and every BLOCK node created here in `poplevel' is important
if (type == error_mark_node)
return;
- /* If this type of object needs a cleanup, and control may
- jump past it, make a new binding level so that it is cleaned
- up only when it is initialized first. */
+ /* If this type of object needs a cleanup, but we're not allowed to
+ add any more objects with cleanups to the current scope, create a
+ new binding level. */
if (TYPE_NEEDS_DESTRUCTOR (type)
&& current_binding_level->more_cleanups_ok == 0)
- pushlevel_temporary (1);
+ {
+ keep_next_level (2);
+ pushlevel (1);
+ clear_last_expr ();
+ add_scope_stmt (/*begin_p=*/1, /*partial_p=*/1);
+ }
if (initialized)
/* Is it valid for this decl to have an initializer at all?
vtbls_set_up_p = 1;
}
+/* Add a scope-statement to the statement-tree. BEGIN_P indicates
+ whether this statements opens or closes a scope. PARTIAL_P is true
+ for a partial scope, i.e, the scope that begins after a label when
+ an object that needs a cleanup is created. */
+
+void
+add_scope_stmt (begin_p, partial_p)
+ int begin_p;
+ int partial_p;
+{
+ tree ss;
+
+ /* Build the statement. */
+ ss = build_min_nt (SCOPE_STMT);
+ SCOPE_BEGIN_P (ss) = begin_p;
+ SCOPE_PARTIAL_P (ss) = partial_p;
+
+ /* If we're finishing a scope, figure out whether the scope was
+ really necessary. */
+ if (!begin_p)
+ {
+ SCOPE_NULLIFIED_P (ss) = !kept_level_p ();
+ SCOPE_NULLIFIED_P (TREE_VALUE (current_scope_stmt_stack))
+ = SCOPE_NULLIFIED_P (ss);
+ }
+
+ /* Keep the scope stack up to date. */
+ if (begin_p)
+ current_scope_stmt_stack
+ = tree_cons (NULL_TREE, ss, current_scope_stmt_stack);
+ else
+ current_scope_stmt_stack = TREE_CHAIN (current_scope_stmt_stack);
+
+ /* Add the new statement to the statement-tree. */
+ add_tree (ss);
+}
+
/* Begin a new scope. */
void
&& !current_function->x_whole_function_mode_p)
expand_start_bindings (0);
else if (building_stmt_tree () && !processing_template_decl)
- {
- tree ss = build_min_nt (SCOPE_STMT);
- SCOPE_BEGIN_P (ss) = 1;
- add_tree (ss);
- current_scope_stmt_stack
- = tree_cons (NULL_TREE, ss, current_scope_stmt_stack);
- }
+ add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
}
}
expand_end_bindings (getdecls (), kept_level_p (), 0);
else if (building_stmt_tree () && !processing_template_decl)
{
- tree ss = build_min_nt (SCOPE_STMT);
- SCOPE_NULLIFIED_P (ss) = !kept_level_p ();
- SCOPE_NULLIFIED_P (TREE_VALUE (current_scope_stmt_stack))
- = SCOPE_NULLIFIED_P (ss);
- add_tree (ss);
- current_scope_stmt_stack = TREE_CHAIN (current_scope_stmt_stack);
+ add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
/* When not in function-at-a-time mode, expand_end_bindings
will warn about unused variables. But, in
if (SCOPE_BEGIN_P (t))
expand_start_bindings (2 * SCOPE_NULLIFIED_P (t));
else if (SCOPE_END_P (t))
- expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t), 0);
+ expand_end_bindings (NULL_TREE, !SCOPE_NULLIFIED_P (t),
+ SCOPE_PARTIAL_P (t));
break;
case RETURN_INIT:
--- /dev/null
+// Build don't link:
+// Special g++ Options: -g
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+struct S
+{
+ ~S ();
+};
+
+void f ()
+{
+ t:
+ S s3;
+}
+
--- /dev/null
+// Build don't link:
+// Origin: Mark Mitchell <mark@codesourcery.com>
+
+struct S
+{
+ S ();
+ ~S ();
+};
+
+void f ()
+{
+ {
+ S s1;
+
+ t:
+ S s2;
+ ;
+ }
+
+ goto t; // ERROR - jump avoids initialization of `s1'
+}