aboutsummaryrefslogtreecommitdiff
path: root/gcc/c-semantics.c
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/c-semantics.c')
-rw-r--r--gcc/c-semantics.c113
1 files changed, 113 insertions, 0 deletions
diff --git a/gcc/c-semantics.c b/gcc/c-semantics.c
index 2e0d537..eea9f92 100644
--- a/gcc/c-semantics.c
+++ b/gcc/c-semantics.c
@@ -36,6 +36,119 @@ Boston, MA 02111-1307, USA. */
#include "output.h"
#include "timevar.h"
+static tree prune_unused_decls PARAMS ((tree *, int *, void *));
+
+/* Create an empty statement tree rooted at T. */
+
+void
+begin_stmt_tree (t)
+ tree *t;
+{
+ /* We create a trivial EXPR_STMT so that last_tree is never NULL in
+ what follows. We remove the extraneous statement in
+ finish_stmt_tree. */
+ *t = build_nt (EXPR_STMT, void_zero_node);
+ last_tree = *t;
+ last_expr_type = NULL_TREE;
+}
+
+/* T is a statement. Add it to the statement-tree. */
+
+void
+add_stmt (t)
+ tree t;
+{
+ /* Add T to the statement-tree. */
+ TREE_CHAIN (last_tree) = t;
+ last_tree = t;
+ /* When we expand a statement-tree, we must know whether or not the
+ statements are full-expresions. We record that fact here. */
+ STMT_IS_FULL_EXPR_P (last_tree) = stmts_are_full_exprs_p ();
+}
+
+/* Remove declarations of internal variables that are not used from a
+ stmt tree. To qualify, the variable must have a name and must have
+ a zero DECL_SOURCE_LINE. We tried to remove all variables for
+ which TREE_USED was false, but it turns out that there's tons of
+ variables for which TREE_USED is false but that are still in fact
+ used. */
+
+static tree
+prune_unused_decls (tp, walk_subtrees, data)
+ tree *tp;
+ int *walk_subtrees ATTRIBUTE_UNUSED;
+ void *data ATTRIBUTE_UNUSED;
+{
+ tree t = *tp;
+
+ if (t == NULL_TREE)
+ {
+ *walk_subtrees = 0;
+ return NULL_TREE;
+ }
+
+ if (TREE_CODE (t) == DECL_STMT)
+ {
+ tree d = DECL_STMT_DECL (t);
+ if (!TREE_USED (d) && DECL_NAME (d) && DECL_SOURCE_LINE (d) == 0)
+ {
+ *tp = TREE_CHAIN (t);
+ /* Recurse on the new value of tp, otherwise we will skip
+ the next statement. */
+ return prune_unused_decls (tp, walk_subtrees, data);
+ }
+ }
+ else if (TREE_CODE (t) == SCOPE_STMT)
+ {
+ /* Remove all unused decls from the BLOCK of this SCOPE_STMT. */
+ tree block = SCOPE_STMT_BLOCK (t);
+
+ if (block)
+ {
+ tree *vp;
+
+ for (vp = &BLOCK_VARS (block); *vp; )
+ {
+ tree v = *vp;
+ if (! TREE_USED (v) && DECL_NAME (v) && DECL_SOURCE_LINE (v) == 0)
+ *vp = TREE_CHAIN (v); /* drop */
+ else
+ vp = &TREE_CHAIN (v); /* advance */
+ }
+ /* If there are now no variables, the entire BLOCK can be dropped.
+ (This causes SCOPE_NULLIFIED_P (t) to be true.) */
+ if (BLOCK_VARS (block) == NULL_TREE)
+ SCOPE_STMT_BLOCK (t) = NULL_TREE;
+ }
+ }
+ return NULL_TREE;
+}
+
+/* Finish the statement tree rooted at T. */
+
+void
+finish_stmt_tree (t)
+ tree *t;
+{
+ tree stmt;
+
+ /* Remove the fake extra statement added in begin_stmt_tree. */
+ stmt = TREE_CHAIN (*t);
+ *t = stmt;
+ last_tree = NULL_TREE;
+
+ /* Remove unused decls from the stmt tree. */
+ walk_stmt_tree (t, prune_unused_decls, NULL);
+
+ if (cfun)
+ {
+ /* The line-number recorded in the outermost statement in a function
+ is the line number of the end of the function. */
+ STMT_LINENO (stmt) = lineno;
+ STMT_LINENO_FOR_FN_P (stmt) = 1;
+ }
+}
+
/* Build a generic statement based on the given type of node and
arguments. Similar to `build_nt', except that we set
TREE_COMPLEXITY to be the current line number. */