From: Mark Mitchell Date: Sun, 7 Apr 2002 06:09:27 +0000 (+0000) Subject: re PR c++/5571 (crash in initialization of a static variable) X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=0154eaa8122a7a848fd40a79d30d3835508e2ab6;p=gcc.git re PR c++/5571 (crash in initialization of a static variable) PR c++/5571 * stor-layout.c (layout_decl): Reset the RTL for the decl. * class.c (layout_class_type): Remember incomplete static variables. (finish_struct_1): Call complete_vars, not hack_incomplete_structures. * cp-tree.h (hack_incomplete_structures): Rename to ... (complete_vars): ... this. (struct saved_scope): Remove incomplete. (namespace_scope_incomplete): Remove. * decl.c (struct binding_level): Remove incomplete. (incomplete_vars): New variable. (mark_binding_level): Don't mark incomplete. (print_binding_level): Don't print it. (mark_saved_scope): Don't mark incomplete. (pushdecl): Use maybe_register_incopmlete_var. (cxx_init_decl_processing): Register incomplete_vars for GC. (start_decl_1): Clarify error message. (hack_incomplete_vars): Remove. (maybe_register_incomplete_var): New function. (complete_vars): Likewise. * g++.dg/opt/static2.C: New test. From-SVN: r51978 --- diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 62631007bb7..abe29ba04a0 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -37,6 +37,9 @@ 2002-04-06 Mark Mitchell + PR c++/5571 + * stor-layout.c (layout_decl): Reset the RTL for the decl. + PR opt/5120 * sibcall.c (optimize_sibling_and_tail_recursive_call): Clear RTX_UNCHANGING_P for the functions arguments when a tail call diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index e739e2a0a11..1d2470abf47 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,26 @@ +2002-04-06 Mark Mitchell + + PR c++/5571 + * class.c (layout_class_type): Remember incomplete static + variables. + (finish_struct_1): Call complete_vars, not + hack_incomplete_structures. + * cp-tree.h (hack_incomplete_structures): Rename to ... + (complete_vars): ... this. + (struct saved_scope): Remove incomplete. + (namespace_scope_incomplete): Remove. + * decl.c (struct binding_level): Remove incomplete. + (incomplete_vars): New variable. + (mark_binding_level): Don't mark incomplete. + (print_binding_level): Don't print it. + (mark_saved_scope): Don't mark incomplete. + (pushdecl): Use maybe_register_incopmlete_var. + (cxx_init_decl_processing): Register incomplete_vars for GC. + (start_decl_1): Clarify error message. + (hack_incomplete_vars): Remove. + (maybe_register_incomplete_var): New function. + (complete_vars): Likewise. + 2002-04-06 Jason Merrill PR c++/4934 diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 8ce3fc7ab46..ba28e849554 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -4898,6 +4898,18 @@ layout_class_type (t, empty_p, vfuns_p, if (TREE_CODE (field) != FIELD_DECL) { place_field (rli, field); + /* If the static data member has incomplete type, keep track + of it so that it can be completed later. (The handling + of pending statics in finish_record_layout is + insufficient; consider: + + struct S1; + struct S2 { static S1 s1; }; + + At this point, finish_record_layout will be called, but + S1 is still incomplete.) */ + if (TREE_CODE (field) == VAR_DECL) + maybe_register_incomplete_var (field); continue; } @@ -5240,7 +5252,7 @@ finish_struct_1 (t) && DECL_VINDEX (TREE_VEC_ELT (CLASSTYPE_METHOD_VEC (t), 1)) == NULL_TREE) warning ("`%#T' has virtual functions but non-virtual destructor", t); - hack_incomplete_structures (t); + complete_vars (t); if (warn_overloaded_virtual) warn_hidden (t); diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 8b3a256d5b7..1cd7d4add53 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -730,7 +730,6 @@ struct saved_scope tree x_previous_class_type; tree x_previous_class_values; tree x_saved_tree; - tree incomplete; tree lookups; tree last_parms; @@ -795,10 +794,6 @@ struct saved_scope #define previous_class_values scope_chain->x_previous_class_values -/* A list of the declarations with incomplete type at namespace scope. */ - -#define namespace_scope_incomplete scope_chain->incomplete - /* A list of private types mentioned, for deferred access checking. */ #define type_lookups scope_chain->lookups @@ -3766,7 +3761,8 @@ extern void finish_function_body PARAMS ((tree)); extern tree finish_function PARAMS ((int)); extern tree start_method PARAMS ((tree, tree, tree)); extern tree finish_method PARAMS ((tree)); -extern void hack_incomplete_structures PARAMS ((tree)); +extern void maybe_register_incomplete_var PARAMS ((tree)); +extern void complete_vars PARAMS ((tree)); extern void finish_stmt PARAMS ((void)); extern void print_other_binding_stack PARAMS ((struct binding_level *)); extern void revert_static_member_fn PARAMS ((tree)); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 78f1b14a7f3..383991f0924 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -398,10 +398,6 @@ struct binding_level /* The binding level which this one is contained in (inherits from). */ struct binding_level *level_chain; - /* List of decls in `names' that have incomplete - structure or union types. */ - tree incomplete; - /* List of VAR_DECLS saved from a previous for statement. These would be dead in ISO-conforming code, but might be referenced in ARM-era code. These are stored in a @@ -484,6 +480,12 @@ static struct binding_level *global_binding_level; static int keep_next_level_flag; +/* A TREE_LIST of VAR_DECLs. The TREE_PURPOSE is a RECORD_TYPE or + UNION_TYPE; the TREE_VALUE is a VAR_DECL with that type. At the + time the VAR_DECL was declared, the type was incomplete. */ + +static tree incomplete_vars; + #if defined(DEBUG_CP_BINDING_LEVELS) static int binding_depth = 0; static int is_class_level = 0; @@ -1957,7 +1959,6 @@ mark_binding_level (arg) ggc_mark_tree (lvl->shadowed_labels); ggc_mark_tree (lvl->blocks); ggc_mark_tree (lvl->this_class); - ggc_mark_tree (lvl->incomplete); ggc_mark_tree (lvl->dead_vars_from_for); } } @@ -1995,8 +1996,6 @@ print_binding_level (lvl) int i = 0, len; fprintf (stderr, " blocks="); fprintf (stderr, HOST_PTR_PRINTF, lvl->blocks); - fprintf (stderr, " n_incomplete=%d parm_flag=%d keep=%d", - list_length (lvl->incomplete), lvl->parm_flag, lvl->keep); if (lvl->tag_transparent) fprintf (stderr, " tag-transparent"); if (lvl->more_cleanups_ok) @@ -2397,7 +2396,6 @@ mark_saved_scope (arg) ggc_mark_tree (t->x_previous_class_type); ggc_mark_tree (t->x_previous_class_values); ggc_mark_tree (t->x_saved_tree); - ggc_mark_tree (t->incomplete); ggc_mark_tree (t->lookups); mark_stmt_tree (&t->x_stmt_tree); @@ -4242,22 +4240,8 @@ pushdecl (x) if (TREE_CODE (x) == FUNCTION_DECL) check_default_args (x); - /* Keep count of variables in this level with incomplete type. */ - if (TREE_CODE (x) == VAR_DECL - && TREE_TYPE (x) != error_mark_node - && ((!COMPLETE_TYPE_P (TREE_TYPE (x)) - && PROMOTES_TO_AGGR_TYPE (TREE_TYPE (x), ARRAY_TYPE)) - /* RTTI TD entries are created while defining the type_info. */ - || (TYPE_LANG_SPECIFIC (TREE_TYPE (x)) - && TYPE_BEING_DEFINED (TREE_TYPE (x))))) - { - if (namespace_bindings_p ()) - namespace_scope_incomplete - = tree_cons (NULL_TREE, x, namespace_scope_incomplete); - else - current_binding_level->incomplete - = tree_cons (NULL_TREE, x, current_binding_level->incomplete); - } + if (TREE_CODE (x) == VAR_DECL) + maybe_register_incomplete_var (x); } if (need_new_binding) @@ -6649,6 +6633,7 @@ cxx_init_decl_processing () ggc_add_tree_root (¤t_lang_name, 1); ggc_add_tree_root (&static_aggregates, 1); ggc_add_tree_root (&free_bindings, 1); + ggc_add_tree_root (&incomplete_vars, 1); } /* Generate an initializer for a function naming variable from @@ -7430,7 +7415,7 @@ start_decl_1 (decl) if ((! processing_template_decl || ! uses_template_parms (type)) && !COMPLETE_TYPE_P (complete_type (type))) { - error ("aggregate `%#D' has incomplete type and cannot be initialized", + error ("aggregate `%#D' has incomplete type and cannot be defined", decl); /* Change the type so that assemble_variable will give DECL an rtl we can live with: (mem (const_int 0)). */ @@ -14432,72 +14417,60 @@ finish_method (decl) return decl; } -/* Called when a new struct TYPE is defined. - If this structure or union completes the type of any previous - variable declaration, lay it out and output its rtl. */ + +/* VAR is a VAR_DECL. If its type is incomplete, remember VAR so that + we can lay it out later, when and if its type becomes complete. */ void -hack_incomplete_structures (type) - tree type; +maybe_register_incomplete_var (var) + tree var; { - tree *list; - struct binding_level *level; + my_friendly_assert (TREE_CODE (var) == VAR_DECL, 20020406); - if (!type) /* Don't do this for class templates. */ - return; - - if (namespace_bindings_p ()) - { - level = 0; - list = &namespace_scope_incomplete; - } - else + /* Keep track of variables with incomplete types. */ + if (!processing_template_decl && TREE_TYPE (var) != error_mark_node + && DECL_EXTERNAL (var)) { - level = innermost_nonclass_level (); - list = &level->incomplete; + tree inner_type = TREE_TYPE (var); + + while (TREE_CODE (inner_type) == ARRAY_TYPE) + inner_type = TREE_TYPE (inner_type); + inner_type = TYPE_MAIN_VARIANT (inner_type); + + if ((!COMPLETE_TYPE_P (inner_type) && CLASS_TYPE_P (inner_type)) + /* RTTI TD entries are created while defining the type_info. */ + || (TYPE_LANG_SPECIFIC (inner_type) + && TYPE_BEING_DEFINED (inner_type))) + incomplete_vars = tree_cons (inner_type, var, incomplete_vars); } +} - while (1) - { - while (*list) - { - tree decl = TREE_VALUE (*list); - if ((decl && TREE_TYPE (decl) == type) - || (TREE_TYPE (decl) - && TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE - && TREE_TYPE (TREE_TYPE (decl)) == type)) - { - int toplevel = toplevel_bindings_p (); - if (TREE_CODE (TREE_TYPE (decl)) == ARRAY_TYPE - && TREE_TYPE (TREE_TYPE (decl)) == type) - layout_type (TREE_TYPE (decl)); - layout_decl (decl, 0); - rest_of_decl_compilation (decl, NULL, toplevel, 0); - if (! toplevel) - { - tree cleanup; - expand_decl (decl); - cleanup = cxx_maybe_build_cleanup (decl); - expand_decl_init (decl); - if (! expand_decl_cleanup (decl, cleanup)) - error ("parser lost in parsing declaration of `%D'", - decl); - } - *list = TREE_CHAIN (*list); - } - else - list = &TREE_CHAIN (*list); - } +/* Called when a class type (given by TYPE) is defined. If there are + any existing VAR_DECLs whose type hsa been completed by this + declaration, update them now. */ - /* Keep looking through artificial binding levels generated - for local variables. */ - if (level && level->keep == 2) +void +complete_vars (type) + tree type; +{ + tree *list = &incomplete_vars; + + my_friendly_assert (CLASS_TYPE_P (type), 20020406); + while (*list) + { + if (same_type_p (type, TREE_PURPOSE (*list))) { - level = level->level_chain; - list = &level->incomplete; + tree var = TREE_VALUE (*list); + /* Make sure that the type of the VAR has been laid out. It + might not have been if the type of VAR is an array. */ + layout_type (TREE_TYPE (var)); + /* Lay out the variable itself. */ + layout_decl (var, 0); + /* Remove this entry from the list. */ + *list = TREE_CHAIN (*list); } else - break; + list = &TREE_CHAIN (*list); } } diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index baf26dddba1..fbf5e4f42ad 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -461,6 +461,11 @@ layout_decl (decl, known_align) larger_than_size); } } + + /* If there was already RTL for this DECL, as for a variable with an + incomplete type whose type is completed later, update the RTL. */ + if (DECL_RTL_SET_P (decl)) + make_decl_rtl (decl, NULL); } /* Hook for a front-end function that can modify the record layout as needed diff --git a/gcc/testsuite/ChangeLog b/gcc/testsuite/ChangeLog index ddd75d41ea8..c71c02ebbe2 100644 --- a/gcc/testsuite/ChangeLog +++ b/gcc/testsuite/ChangeLog @@ -1,3 +1,8 @@ +2002-04-06 Mark Mitchell + + PR c++/5571 + * g++.dg/opt/static2.C: New test. + 2002-04-06 Mark Mitchell PR c/5120 diff --git a/gcc/testsuite/g++.dg/opt/static2.C b/gcc/testsuite/g++.dg/opt/static2.C new file mode 100644 index 00000000000..e2ecd13c572 --- /dev/null +++ b/gcc/testsuite/g++.dg/opt/static2.C @@ -0,0 +1,13 @@ +// Origin: reichelt@igpm.rwth-aachen.de +// PR 5571 +// { dg-options "-O2" } + +template struct A {}; + +struct B +{ + static A a; + void f() { a; } +}; + +A B::a = A();