1999-12-04 Mark Mitchell <mark@codesourcery.com>
+ * cp-tree.def (SCOPE_STMT): Take one operand.
+ * cp-tree.h (SCOPE_STMT_BLOCK): New macro.
+ (SCOPE_NULLIFIED_P): Redefine.
+ (SCOPE_NO_CLEANUPS_P): New macro.
+ (add_scope_stmt): Change prototype.
+ * decl.c (poplevel): Tidy. Warn about unused variables here.
+ Record SCOPE_STMT_BLOCKs.
+ (finish_function): Keep DECL_INITIAL for functions that might be
+ inlined.
+ * ir.texi: Document SCOPE_NO_CLEANUPS_P.
+ * semantics.c: Include rtl.h.
+ (add_scope_stmt): Return the new scope statement and, for an
+ end-of-scope statement, its matching begin statement. Don't set
+ SCOPE_NULLIFIED_P.
+ (do_pushlevel): Simplify, now that we are always
+ function-at-a-time.
+ (do_poplevel): Likewise. Record SCOPE_STMT_BLOCKs.
+ (expand_stmt): Don't call expand_start_bindings or
+ expand_end_bindings for a scope with SCOPE_NO_CLEANUPS_P set.
+ * tree.c (copy_tree_r): Clear SCOPE_STMT_BLOCK rather than setting
+ SCOPE_NULLIFIED_P.
+
* decl2.c (pending_statics_used): Make it a macro.
(saved_inlines_used): Likewise.
(finish_static_data_member_decl): Use VARRAY_PUSH_TREE.
SCOPE_BEGIN_P holds, then this is the start of a scope. If
SCOPE_END_P holds, then this is the end of a scope. If
SCOPE_NULLIFIED_P holds then there turned out to be no variables in
- this scope. */
-DEFTREECODE (SCOPE_STMT, "scope_stmt", 'e', 0)
+ this scope. The SCOPE_STMT_BLOCK is the BLOCK containing the
+ variables declared in this scope. */
+DEFTREECODE (SCOPE_STMT, "scope_stmt", 'e', 1)
DEFTREECODE (CTOR_INITIALIZER, "ctor_initializer", 'e', 2)
DEFTREECODE (CASE_LABEL, "case_label", 'e', 2)
DEFTREECODE (RETURN_INIT, "return_init", 'e', 2)
(TREE_REFERENCE_EXPR) (in NON_LVALUE_EXPR) (commented-out).
ICS_BAD_FLAG (in _CONV)
FN_TRY_BLOCK_P (in TRY_BLOCK)
- SCOPE_NULLIFIED_P (in SCOPE_STMT)
+ SCOPE_NO_CLEANUPS_P (in SCOPE_STMT)
4: BINFO_NEW_VTABLE_MARKED.
TREE_HAS_CONSTRUCTOR (in INDIRECT_REF, SAVE_EXPR, CONSTRUCTOR,
or FIELD_DECL).
#define SCOPE_END_P(NODE) \
(!SCOPE_BEGIN_P (SCOPE_STMT_CHECK (NODE)))
+/* The BLOCK containing the declarations contained in this scope. */
+#define SCOPE_STMT_BLOCK(NODE) \
+ (TREE_OPERAND (SCOPE_STMT_CHECK (NODE), 0))
+
/* Nonzero if this CTOR_STMT is for the beginning of a constructor. */
#define CTOR_BEGIN_P(NODE) \
(TREE_LANG_FLAG_0 (CTOR_STMT_CHECK (NODE)))
/* Nonzero for a SCOPE_STMT if there were no variables in this scope. */
#define SCOPE_NULLIFIED_P(NODE) \
+ (SCOPE_STMT_BLOCK ((NODE)) == NULL_TREE)
+
+/* Nonzero for a SCOPE_STMT which represents a lexical scope, but
+ which should be treated as non-existant from the point of view of
+ running cleanup actions. */
+#define SCOPE_NO_CLEANUPS_P(NODE) \
(TREE_LANG_FLAG_3 (SCOPE_STMT_CHECK (NODE)))
/* Nonzero for a SCOPE_STMT if this statement is for a partial scope.
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 tree 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
/* Output any nested inline functions within this block
if they weren't already output. */
-
for (decl = decls; decl; decl = TREE_CHAIN (decl))
if (TREE_CODE (decl) == FUNCTION_DECL
&& ! TREE_ASM_WRITTEN (decl)
}
}
+ /* When not in function-at-a-time mode, expand_end_bindings will
+ warn about unused variables. But, in function-at-a-time mode
+ expand_end_bindings is not passed the list of variables in the
+ current scope, and therefore no warning is emitted. So, we
+ explicitly warn here. */
+ if (!processing_template_decl)
+ warn_about_unused_variables (getdecls ());
+
/* If there were any declarations or structure tags in that level,
or if this level is a function body,
create a BLOCK to record them for the life of this function. */
-
block = NULL_TREE;
block_previously_created = (current_binding_level->this_block != NULL_TREE);
if (block_previously_created)
}
/* In each subblock, record that this is its superior. */
-
if (keep >= 0)
for (link = subblocks; link; link = TREE_CHAIN (link))
BLOCK_SUPERCONTEXT (link) = block;
current_binding_level->blocks
= chainon (current_binding_level->blocks, subblocks);
+ /* 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;
+
/* Take care of compiler's internal binding structures. */
if (tmp == 2)
{
- 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". */
+ tree scope_stmts;
+
+ scope_stmts
+ = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/1);
if (block)
- TREE_USED (block) = 1;
+ {
+ SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
+ SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
+ }
+
block = poplevel (keep, reverse, functionbody);
}
- /* 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;
return block;
}
--function_depth;
- if (!DECL_SAVED_INSNS (fndecl) && !DECL_SAVED_FUNCTION_DATA (fndecl))
+ if (!DECL_SAVED_INSNS (fndecl) && !DECL_SAVED_FUNCTION_DATA (fndecl)
+ && !(flag_inline_trees && DECL_INLINE (fndecl)))
{
tree t;
scope; if @code{SCOPE_END_P} holds this statement represents the end of
a scope. On exit from a scope, all cleanups from @code{CLEANUP_STMT}s
occurring in the scope must be run, in reverse order to the order in
-which they were encountered. If @code{SCOPE_NULLIFIED_P} holds of the
-scope, back-ends should behave as if the @code{SCOPE_STMT} were not
-present at all.
+which they were encountered. If @code{SCOPE_NULLIFIED_P} or
+@code{SCOPE_NO_CLEANUPS_P} holds of the scope, back-ends should behave
+as if the @code{SCOPE_STMT} were not present at all.
@item START_CATCH_STMT
#include "toplev.h"
#include "flags.h"
#include "ggc.h"
+#include "rtl.h"
/* There routines provide a modular interface to perform many parsing
operations. They may therefore be used during actual parsing, or
/* 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. */
+ an object that needs a cleanup is created. If BEGIN_P is nonzero,
+ returns a new TREE_LIST representing the top of the SCOPE_STMT
+ stack. The TREE_PURPOSE is the new SCOPE_STMT. If BEGIN_P is
+ zero, returns a TREE_LIST whose TREE_VALUE is the new SCOPE_STMT,
+ and whose TREE_PURPOSE is the matching SCOPE_STMT iwth
+ SCOPE_BEGIN_P set. */
-void
+tree
add_scope_stmt (begin_p, partial_p)
int begin_p;
int partial_p;
{
tree ss;
+ tree top;
/* Build the statement. */
- ss = build_min_nt (SCOPE_STMT);
+ ss = build_min_nt (SCOPE_STMT, NULL_TREE);
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);
+ {
+ current_scope_stmt_stack
+ = tree_cons (ss, NULL_TREE, current_scope_stmt_stack);
+ top = current_scope_stmt_stack;
+ }
else
- current_scope_stmt_stack = TREE_CHAIN (current_scope_stmt_stack);
+ {
+ top = current_scope_stmt_stack;
+ TREE_VALUE (top) = ss;
+ current_scope_stmt_stack = TREE_CHAIN (top);
+ }
/* Add the new statement to the statement-tree. */
add_tree (ss);
+
+ return top;
}
/* Begin a new scope. */
pushlevel (0);
if (!building_stmt_tree ()
&& !current_function->x_whole_function_mode_p)
- expand_start_bindings (0);
- else if (building_stmt_tree () && !processing_template_decl)
+ my_friendly_abort (19991129);
+
+ if (building_stmt_tree () && !processing_template_decl)
add_scope_stmt (/*begin_p=*/1, /*partial_p=*/0);
}
}
tree
do_poplevel ()
{
- tree t = NULL_TREE;
+ tree block = NULL_TREE;
if (stmts_are_full_exprs_p)
{
- if (!building_stmt_tree ()
- && !current_function->x_whole_function_mode_p)
- expand_end_bindings (getdecls (), kept_level_p (), 0);
- else if (building_stmt_tree () && !processing_template_decl)
+ tree scope_stmts;
+ int keep = kept_level_p ();
+
+ if (building_stmt_tree () && !processing_template_decl)
+ scope_stmts = add_scope_stmt (/*begin_p=*/0, /*partial_p=*/0);
+ else
+ scope_stmts = NULL_TREE;
+
+ block = poplevel (kept_level_p (), 1, 0);
+ if (block && !processing_template_decl)
{
- 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
- function-at-a-time mode expand_end_bindings is not passed
- the list of variables in the current scope, and therefore
- no warning is emitted. So, we explicitly warn here. */
- warn_about_unused_variables (getdecls ());
+ SCOPE_STMT_BLOCK (TREE_PURPOSE (scope_stmts)) = block;
+ SCOPE_STMT_BLOCK (TREE_VALUE (scope_stmts)) = block;
}
-
- t = poplevel (kept_level_p (), 1, 0);
}
- return t;
+
+ return block;
}
/* Finish a parenthesized expression EXPR. */
break;
case SCOPE_STMT:
- 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),
- SCOPE_PARTIAL_P (t));
+ if (!SCOPE_NO_CLEANUPS_P (t))
+ {
+ 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),
+ SCOPE_PARTIAL_P (t));
+ }
+ else if (!SCOPE_NULLIFIED_P (t))
+ emit_note (NULL,
+ (SCOPE_BEGIN_P (t)
+ ? NOTE_INSN_BLOCK_BEG
+ : NOTE_INSN_BLOCK_END));
break;
case RETURN_INIT:
/* For now, we don't update BLOCKs when we make copies. So, we
have to nullify all scope-statements. */
if (TREE_CODE (*tp) == SCOPE_STMT)
- SCOPE_NULLIFIED_P (*tp) = 1;
+ SCOPE_STMT_BLOCK (*tp) = NULL_TREE;
}
else if (code == TEMPLATE_TEMPLATE_PARM)
/* These must be copied specially. */
--- /dev/null
+// Build don't link:
+// Origin: Mark Mitchell <mark@codesourcery.com>
+// Special g++ Options: -Wunused
+
+struct S
+{
+ S ();
+ ~S ();
+};
+
+void f ()
+{
+ {
+ S s1;
+ int j; // WARNING - unused
+
+ t: // WARNING - unused
+ S s2;
+ }
+}