aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tromey@redhat.com>2008-02-21 18:16:35 +0000
committerTom Tromey <tromey@redhat.com>2008-02-21 18:16:35 +0000
commitc780f8ae4984f67e934c5dfab3ecd456dd45af7e (patch)
tree2a7973ba22470e082b64ca238ea46addf63491cc
parent1e902f2d33f756f8865aff8ac0de556e718c5ca2 (diff)
* c-gimplify.c (c_gimplify_expr) <VIEW_CONVERT_EXPR>: Update
assertion. * c-decl.c (all_global_decls): New global. (pop_scope_internal): New function. (pop_scope): Use it. (pop_file_scope): Initialize all_global_decls. Use pop_scope_internal. (c_clear_binding_stack): Use pop_scope_internal. (ext_block): Remove. (c_smash_decls): Change type of 'result'. Remove 'list' argument; add 'globals' argument. Smash field types of records and unions. (get_smashed_type): Don't smash field types of records and unions. (hand_off_decls): Walk DECL_ARGUMENTS of function. (c_write_global_declarations): Use all_global_decls. (c_init_decl_processing): Initialize all_global_decls. * c-parser.c (struct can_reuse_hunk_data) <parser>: Remove. (traverse_check_statics): New function. (can_reuse_hunk): Call traverse_check_statics. git-svn-id: https://gcc.gnu.org/svn/gcc/branches/incremental-compiler@132525 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/ChangeLog23
-rw-r--r--gcc/c-decl.c144
-rw-r--r--gcc/c-gimplify.c8
-rw-r--r--gcc/c-parser.c65
4 files changed, 163 insertions, 77 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog
index 73bb27a4946..9d11270af0d 100644
--- a/gcc/ChangeLog
+++ b/gcc/ChangeLog
@@ -1,3 +1,26 @@
+2008-02-21 Tom Tromey <tromey@redhat.com>
+
+ * c-gimplify.c (c_gimplify_expr) <VIEW_CONVERT_EXPR>: Update
+ assertion.
+ * c-decl.c (all_global_decls): New global.
+ (pop_scope_internal): New function.
+ (pop_scope): Use it.
+ (pop_file_scope): Initialize all_global_decls. Use
+ pop_scope_internal.
+ (c_clear_binding_stack): Use pop_scope_internal.
+ (ext_block): Remove.
+ (c_smash_decls): Change type of 'result'. Remove 'list'
+ argument; add 'globals' argument. Smash field types of records
+ and unions.
+ (get_smashed_type): Don't smash field types of records and
+ unions.
+ (hand_off_decls): Walk DECL_ARGUMENTS of function.
+ (c_write_global_declarations): Use all_global_decls.
+ (c_init_decl_processing): Initialize all_global_decls.
+ * c-parser.c (struct can_reuse_hunk_data) <parser>: Remove.
+ (traverse_check_statics): New function.
+ (can_reuse_hunk): Call traverse_check_statics.
+
2008-02-18 Tom Tromey <tromey@redhat.com>
* c-parser.c (c_hack_token): Pop timevar in early return.
diff --git a/gcc/c-decl.c b/gcc/c-decl.c
index 1a259a20617..8e4b55d35e8 100644
--- a/gcc/c-decl.c
+++ b/gcc/c-decl.c
@@ -166,6 +166,11 @@ bool c_override_global_bindings_to_false;
re-initializing the front end (in server mode), these are
re-bound. */
static GTY ((param_is (union tree_node))) htab_t all_c_built_ins;
+
+/* When popping the file and external scopes, we collect the resulting
+ DECLs into this vector. */
+static GTY (()) VEC (tree, gc) *all_global_decls;
+
/* Each c_binding structure describes one binding of an identifier to
a decl. All the decls in a scope - irrespective of namespace - are
@@ -722,10 +727,12 @@ set_type_context (tree type, tree context)
/* Exit a scope. Restore the state of the identifier-decl mappings
that were in effect when this scope was entered. Return a BLOCK
node containing all the DECLs in this scope that are of interest
- to debug info generation. */
+ to debug info generation. If RESULTS is not NULL, DECLs are not
+ put into the resulting block, but are instead pushed into the
+ supplied vector. */
-tree
-pop_scope (void)
+static tree
+pop_scope_internal (VEC (tree, gc) **results)
{
struct c_scope *scope = current_scope;
tree block, context, p;
@@ -794,6 +801,7 @@ pop_scope (void)
warn_for_unused_label (p);
/* Labels go in BLOCK_VARS. */
+ gcc_assert (!results);
TREE_CHAIN (p) = BLOCK_VARS (block);
BLOCK_VARS (block) = p;
gcc_assert (I_LABEL_BINDING (b->id) == b);
@@ -867,8 +875,20 @@ pop_scope (void)
binding in the home scope. */
if (!b->nested)
{
- TREE_CHAIN (p) = BLOCK_VARS (block);
- BLOCK_VARS (block) = p;
+ /* If RESULTS is supplied, push the decl there. We use
+ this rather than TREE_CHAIN because we may see a DECL
+ in multiple translation units, and changing
+ TREE_CHAIN destroys the list structure. */
+ if (results)
+ {
+ gcc_assert (scope == external_scope || scope == file_scope);
+ VEC_safe_push (tree, gc, *results, p);
+ }
+ else
+ {
+ TREE_CHAIN (p) = BLOCK_VARS (block);
+ BLOCK_VARS (block) = p;
+ }
}
/* If this is the file scope, and we are processing more
than one translation unit in this compilation, set
@@ -936,6 +956,14 @@ pop_scope (void)
return block;
}
+/* Like pop_scope_internal, but always supplies a NULL RESULTS
+ argument. */
+tree
+pop_scope (void)
+{
+ return pop_scope_internal (NULL);
+}
+
void
push_file_scope (void)
{
@@ -981,8 +1009,11 @@ pop_file_scope (void)
return;
}
+ if (!all_global_decls)
+ all_global_decls = VEC_alloc (tree, gc, 128);
+
/* Pop off the file scope and close this translation unit. */
- pop_scope ();
+ pop_scope_internal (&all_global_decls);
file_scope = 0;
maybe_apply_pending_pragma_weaks ();
@@ -3000,6 +3031,7 @@ c_init_decl_processing (void)
current_function_decl = 0;
all_translation_units = NULL_TREE;
+ all_global_decls = NULL;
if (!did_it)
gcc_obstack_init (&parser_obstack);
@@ -8224,20 +8256,6 @@ get_smashed_type (htab_t map, tree type)
else
*slot = found;
-
- if ((TREE_CODE (type) == UNION_TYPE || TREE_CODE (type) == RECORD_TYPE)
- && type == TYPE_MAIN_VARIANT (type))
- {
- /* Canonicalize the type of each field. We do this here, and
- not earlier, to avoid infinite recursion in some cases. */
- tree field;
- for (field = TYPE_FIELDS (type); field; field = TREE_CHAIN (field))
- {
- gcc_assert (TREE_CODE (field) == FIELD_DECL);
- TREE_TYPE (field) = get_smashed_type (map, TREE_TYPE (field));
- }
- }
-
return type;
}
@@ -8245,26 +8263,27 @@ get_smashed_type (htab_t map, tree type)
the chain. */
static void
c_smash_decls (htab_t map, struct pointer_set_t *seen,
- VEC (tree, heap) **result, tree list)
+ VEC (tree, gc) *globals,
+ VEC (tree, heap) **result)
{
tree decl;
- for (decl = list; decl; decl = TREE_CHAIN (decl))
+ int ix;
+ for (ix = 0; VEC_iterate (tree, globals, ix, decl); ++ix)
{
tree canonical;
struct c_tree_map_entry entry;
void **slot;
if (! map)
+ continue;
+
+ /* This can happen with --combine. */
+ if (pointer_set_contains (seen, decl))
{
VEC_safe_push (tree, heap, *result, decl);
continue;
}
- /* This can happen with --combine. FIXME: with combine we get
- the wrong result for file-scope variables. */
- if (pointer_set_contains (seen, decl))
- continue;
-
/* The first time we see a decl, we insert its canonical copy
into the result list. If we've already seen the canonical
copy, we simply skip it and move on. */
@@ -8330,6 +8349,23 @@ c_smash_decls (htab_t map, struct pointer_set_t *seen,
else
TREE_TYPE (canonical) = get_smashed_type (map, TREE_TYPE (canonical));
+ /* If we see a struct or union, we want to rewrite its field
+ types now. */
+ if (TREE_CODE (canonical) == TYPE_DECL
+ && TREE_TYPE (canonical) == TYPE_MAIN_VARIANT (TREE_TYPE (canonical))
+ && (TREE_CODE (TREE_TYPE (canonical)) == RECORD_TYPE
+ || TREE_CODE (TREE_TYPE (canonical)) == UNION_TYPE))
+ {
+ tree field;
+ for (field = TYPE_FIELDS (TREE_TYPE (canonical));
+ field;
+ field = TREE_CHAIN (field))
+ {
+ gcc_assert (TREE_CODE (field) == FIELD_DECL);
+ TREE_TYPE (field) = get_smashed_type (map, TREE_TYPE (field));
+ }
+ }
+
pointer_set_insert (seen, canonical);
VEC_safe_push (tree, heap, *result, canonical);
}
@@ -8385,6 +8421,8 @@ hand_off_decls (htab_t map, VEC (tree, heap) *globals)
map, NULL);
walk_tree (&DECL_SAVED_TREE (decl), rewrite_types_and_globals,
map, NULL);
+ walk_tree (&DECL_ARGUMENTS (decl), rewrite_types_and_globals,
+ map, NULL);
c_override_global_bindings_to_false = save;
if (DECL_INITIAL (decl) && DECL_INITIAL (decl) != error_mark_node)
cgraph_finalize_function (decl, false);
@@ -8475,36 +8513,32 @@ c_write_global_declarations_2 (VEC (tree, heap) *globals)
debug_hooks->global_decl (decl);
}
-/* Preserve the external declarations scope across a garbage collect. */
-static GTY(()) tree ext_block;
-
void
c_clear_binding_stack (void)
{
- /* Clear this in case of early exit. */
- ext_block = NULL;
-
/* We don't want to do this if generating a PCH. */
if (pch_file)
return;
/* Close the external scope. */
- /* FIXME: we're keeping ext_block around too long in the server. */
- ext_block = pop_scope ();
+ /* FIXME: we're keeping all_global_decls around too long in the server. */
+ gcc_assert (all_global_decls);
+ pop_scope_internal (&all_global_decls);
external_scope = 0;
gcc_assert (!current_scope);
- if (ext_block)
- {
- tree tmp = BLOCK_VARS (ext_block);
- int flags;
- FILE * stream = dump_begin (TDI_tu, &flags);
- if (stream && tmp)
- {
- dump_node (tmp, flags & ~TDF_SLIM, stream);
- dump_end (TDI_tu, stream);
- }
- }
+ /* FIXME: re-enable this using all_global_decls. */
+/* if (ext_block) */
+/* { */
+/* tree tmp = BLOCK_VARS (ext_block); */
+/* int flags; */
+/* FILE * stream = dump_begin (TDI_tu, &flags); */
+/* if (stream && tmp) */
+/* { */
+/* dump_node (tmp, flags & ~TDF_SLIM, stream); */
+/* dump_end (TDI_tu, stream); */
+/* } */
+/* } */
}
/* This maps trees to their canonical (smashed) variants. This must
@@ -8514,12 +8548,9 @@ static GTY ((param_is (struct c_tree_map_entry))) htab_t lowering_smash_map;
void
c_write_global_declarations (void)
{
- tree t;
- VEC (tree, heap) *all_decls = VEC_alloc (tree, heap, 128);
struct pointer_set_t *seen_decls = NULL;
-
- if (! really_call_malloc (52))
- abort ();
+ VEC (tree, heap) *all_decls = VEC_alloc (tree, heap,
+ VEC_length (tree, all_global_decls));
server_assert_code_generation ();
@@ -8529,12 +8560,8 @@ c_write_global_declarations (void)
/* Smash all the types and decls. If we don't have a smash map,
just fill ALL_DECLS with all the decls on the lists. */
- for (t = all_translation_units; t; t = TREE_CHAIN (t))
- c_smash_decls (lowering_smash_map, seen_decls, &all_decls,
- BLOCK_VARS (DECL_INITIAL (t)));
- if (ext_block)
- c_smash_decls (lowering_smash_map, seen_decls, &all_decls,
- BLOCK_VARS (ext_block));
+ c_smash_decls (lowering_smash_map, seen_decls, all_global_decls,
+ &all_decls);
/* Clean up. */
if (seen_decls)
@@ -8549,6 +8576,7 @@ c_write_global_declarations (void)
if (flag_syntax_only || errorcount || sorrycount || cpp_errors (parse_in)
|| pch_file)
{
+ all_global_decls = NULL;
VEC_free (tree, heap, all_decls);
return;
}
@@ -8571,8 +8599,8 @@ c_write_global_declarations (void)
timevar_pop (TV_SYMOUT);
}
+ all_global_decls = NULL;
VEC_free (tree, heap, all_decls);
- ext_block = NULL;
}
#include "gt-c-decl.h"
diff --git a/gcc/c-gimplify.c b/gcc/c-gimplify.c
index b4cc4b64942..324ab98a030 100644
--- a/gcc/c-gimplify.c
+++ b/gcc/c-gimplify.c
@@ -45,6 +45,7 @@ along with GCC; see the file COPYING3. If not see
#include "tree-dump.h"
#include "c-pretty-print.h"
#include "cgraph.h"
+#include "opts.h"
/* The gimplification pass converts the language-dependent trees
@@ -232,8 +233,11 @@ c_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p ATTRIBUTE_UNUSED)
conversion should be redundant. */
if (C_SMASHED_P (*expr_p))
{
- gcc_assert (TREE_TYPE (*expr_p)
- == TREE_TYPE (TREE_OPERAND (*expr_p, 0)));
+ gcc_assert ((TREE_TYPE (*expr_p)
+ == TREE_TYPE (TREE_OPERAND (*expr_p, 0)))
+ || (num_in_fnames > 1
+ && comptypes (TREE_TYPE (*expr_p),
+ TREE_TYPE (TREE_OPERAND (*expr_p, 0)))));
*expr_p = TREE_OPERAND (*expr_p, 0);
}
return GS_UNHANDLED;
diff --git a/gcc/c-parser.c b/gcc/c-parser.c
index 11f2187f8e0..ce674fee543 100644
--- a/gcc/c-parser.c
+++ b/gcc/c-parser.c
@@ -59,6 +59,7 @@ along with GCC; see the file COPYING3. If not see
#include "md5.h"
#include "server.h"
#include "pointer-set.h"
+#include "opts.h"
/* The reserved keyword table. */
@@ -2099,11 +2100,37 @@ traverse_check_prereq (void **valp, void *ptd)
return true;
}
+/* A hash table iterator callback which checks to see if a
+ hunk_binding_entry declares a static decl. */
+static int
+traverse_check_statics (void **valp, void *ptd)
+{
+ bool *result = (bool *) ptd;
+ struct hunk_binding_entry *entry = (struct hunk_binding_entry *) *valp;
+
+ if (entry->symbol_binding && entry->symbol_binding != hunk_binding_sentinel)
+ {
+ gcc_assert (TREE_CODE_CLASS (TREE_CODE (entry->symbol_binding))
+ == tcc_declaration);
+ /* This is a bit over-eager, in that it would be ok to reuse a
+ decl if it did not come from one of the current compilation
+ units. However, this is an odd case and hopefully and
+ unimportant one. Also, ideally we could reuse a declaration
+ (not definition) here -- but that may mean working some magic
+ in the smashing pass. */
+ if (TREE_STATIC (entry->symbol_binding))
+ {
+ *result = false;
+ return false;
+ }
+ }
+
+ return true;
+}
+
/* Helper state for can_reuse_hunk and check_hunk_binding. */
struct can_reuse_hunk_data
{
- /* The parser. */
- c_parser *parser;
/* The hunk to check for. */
struct parsed_hunk *hunk;
/* The result, or NULL if nothing reusable found. */
@@ -2119,28 +2146,33 @@ check_hunk_binding (void **valp, void *crhd)
{
struct hunk_binding *binding = (struct hunk_binding *) *valp;
struct can_reuse_hunk_data *info = (struct can_reuse_hunk_data *) crhd;
-/* c_parser *parser = info->parser; */
struct parsed_hunk *hunk = info->hunk;
struct parsed_hunk *binding_iter, *self_iter;
bool ok;
- /* We can't re-use a hunk twice in one compilation unit. FIXME:
- this is a weird restriction and I think will go away once we have
- anti-dependencies. The issue here is that if we see 2 decls
- "extern int f;" the second time we will re_bind the same decl,
- eventually tripping over the GC since the decl's chain will point
- to itself (as part of scope popping). */
- /* FIXME: need more testing before really deleting this. */
-#if 0
- if (htab_find (parser->used_hunks, binding))
- return true;
-#endif
-
/* Check prerequisites for this binding. */
ok = true;
htab_traverse_noresize (binding->prereqs, traverse_check_prereq, &ok);
if (!ok)
- return true;
+ {
+ /* Keep looking. */
+ return true;
+ }
+
+ /* If we're compiling with --combine, then we don't want to reuse
+ static decls across compilation units, as this would give the
+ wrong answer. */
+ if (num_in_fnames > 1)
+ {
+ htab_traverse_noresize (binding->binding_map, traverse_check_statics,
+ &ok);
+ if (!ok)
+ {
+ /* Don't bother looking any more. If one instance of the
+ hunk had a static decl, then the rest will as well. */
+ return false;
+ }
+ }
/* If we have a multi-hunk binding, check to make sure the
current stream has the correct contents. */
@@ -2194,7 +2226,6 @@ can_reuse_hunk (c_parser *parser, struct parsed_hunk *hunk,
*out_set = *set_slot;
- info.parser = parser;
info.hunk = hunk;
info.binding = NULL;
info.self_iter = NULL;