diff options
-rw-r--r-- | gcc/ChangeLog | 25 | ||||
-rw-r--r-- | gcc/c-decl.c | 56 | ||||
-rw-r--r-- | gcc/cgraphunit.c | 8 | ||||
-rw-r--r-- | gcc/cp/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/decl.c | 1 | ||||
-rw-r--r-- | gcc/cp/decl2.c | 8 | ||||
-rw-r--r-- | gcc/langhooks.c | 4 | ||||
-rw-r--r-- | gcc/passes.c | 3 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/debug/20050907-1.c | 24 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/debug/dwarf2/var1.c | 10 | ||||
-rw-r--r-- | gcc/testsuite/gcc.dg/debug/dwarf2/var2.c | 14 | ||||
-rw-r--r-- | gcc/toplev.c | 295 | ||||
-rw-r--r-- | gcc/toplev.h | 6 |
13 files changed, 300 insertions, 161 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 2548e32..17e6ee7 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,28 @@ +2005-09-08 Richard Henderson <rth@redhat.com> + + PR debug/23190 + * toplev.c (wrapup_global_declaration_1): Split out ... + (wrapup_global_declaration_2): ... from ... + (wrapup_global_declarations): ... here. Return bool. + (check_global_declaration_1): Split out ... + (check_global_declarations): from here. + (emit_debug_global_declarations): New. + * toplev.h (wrapup_global_declaration_1, wrapup_global_declaration_2, + check_global_declaration_1, emit_debug_global_declarations): Declare. + * c-decl.c (c_write_global_declarations_1): Don't create a vector + of decls. Call wrapup_global_declaration_1, + wrapup_global_declaration_2, check_global_declaration_1 directly. + (c_write_global_declarations_2): New. + (ext_block): New. + (c_write_global_declarations): Call c_write_global_declarations_2. + * langhooks.c (write_global_declarations): Call + emit_debug_global_declarations. + + * cgraphunit.c (cgraph_varpool_remove_unreferenced_decls): Don't + remove decls that have DECL_RTL_SET_P. + * passes.c (rest_of_decl_compilation): Invoke + cgraph_varpool_finalize_decl for all but functions. + 2005-09-08 Eric Botcazou <ebotcazou@libertysurf.fr> * tree-vrp.c (extract_range_from_unary_expr): Do not set the range for diff --git a/gcc/c-decl.c b/gcc/c-decl.c index f3b8d64..49c8904 100644 --- a/gcc/c-decl.c +++ b/gcc/c-decl.c @@ -7540,20 +7540,18 @@ build_cdtor (int method_type, tree cdtors) cgraph_build_static_cdtor (method_type, body, DEFAULT_INIT_PRIORITY); } -/* Perform final processing on one file scope's declarations (or the - external scope's declarations), GLOBALS. */ +/* A subroutine of c_write_global_declarations. Perform final processing + on one file scope's declarations (or the external scope's declarations), + GLOBALS. */ + static void c_write_global_declarations_1 (tree globals) { - size_t len = list_length (globals); - tree *vec = XNEWVEC (tree, len); - size_t i; tree decl; /* Process the decls in the order they were written. */ - for (i = 0, decl = globals; i < len; i++, decl = TREE_CHAIN (decl)) + for (decl = globals; decl; decl = TREE_CHAIN (decl)) { - vec[i] = decl; /* Check for used but undefined static functions using the C standard's definition of "used", and set TREE_NO_WARNING so that check_global_declarations doesn't repeat the check. */ @@ -7566,18 +7564,32 @@ c_write_global_declarations_1 (tree globals) pedwarn ("%q+F used but never defined", decl); TREE_NO_WARNING (decl) = 1; } + + wrapup_global_declaration_1 (decl); + wrapup_global_declaration_2 (decl); + check_global_declaration_1 (decl); } +} - wrapup_global_declarations (vec, len); - check_global_declarations (vec, len); +/* A subroutine of c_write_global_declarations Emit debug information for each + of the declarations in GLOBALS. */ - free (vec); +static void +c_write_global_declarations_2 (tree globals) +{ + tree decl; + + for (decl = globals; decl ; decl = TREE_CHAIN (decl)) + debug_hooks->global_decl (decl); } +/* Preserve the external declarations scope across a garbage collect. */ +static GTY(()) tree ext_block; + void c_write_global_declarations (void) { - tree ext_block, t; + tree t; /* We don't want to do this if generating a PCH. */ if (pch_file) @@ -7593,10 +7605,6 @@ c_write_global_declarations (void) external_scope = 0; gcc_assert (!current_scope); - /* Process all file scopes in this compilation, and the external_scope, - through wrapup_global_declarations and check_global_declarations. */ - for (t = all_translation_units; t; t = TREE_CHAIN (t)) - c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t))); if (ext_block) { tree tmp = BLOCK_VARS (ext_block); @@ -7608,6 +7616,11 @@ c_write_global_declarations (void) dump_end (TDI_tu, stream); } } + + /* Process all file scopes in this compilation, and the external_scope, + through wrapup_global_declarations and check_global_declarations. */ + for (t = all_translation_units; t; t = TREE_CHAIN (t)) + c_write_global_declarations_1 (BLOCK_VARS (DECL_INITIAL (t))); c_write_global_declarations_1 (BLOCK_VARS (ext_block)); /* Generate functions to call static constructors and destructors @@ -7619,6 +7632,19 @@ c_write_global_declarations (void) /* We're done parsing; proceed to optimize and emit assembly. FIXME: shouldn't be the front end's responsibility to call this. */ cgraph_optimize (); + + /* After cgraph has had a chance to emit everything that's going to + be emitted, output debug information for globals. */ + if (errorcount == 0 && sorrycount == 0) + { + timevar_push (TV_SYMOUT); + for (t = all_translation_units; t; t = TREE_CHAIN (t)) + c_write_global_declarations_2 (BLOCK_VARS (DECL_INITIAL (t))); + c_write_global_declarations_2 (BLOCK_VARS (ext_block)); + timevar_pop (TV_SYMOUT); + } + + ext_block = NULL; } #include "gt-c-decl.h" diff --git a/gcc/cgraphunit.c b/gcc/cgraphunit.c index 012cb7c..e357a25 100644 --- a/gcc/cgraphunit.c +++ b/gcc/cgraphunit.c @@ -311,7 +311,13 @@ cgraph_varpool_remove_unreferenced_decls (void) && ((DECL_ASSEMBLER_NAME_SET_P (decl) && TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) || node->force_output - || decide_is_variable_needed (node, decl))) + || decide_is_variable_needed (node, decl) + /* ??? Cgraph does not yet rule the world with an iron hand, + and does not control the emission of debug information. + After a variable has its DECL_RTL set, we must assume that + it may be referenced by the debug information, and we can + no longer elide it. */ + || DECL_RTL_SET_P (decl))) cgraph_varpool_mark_needed_node (node); node = next; diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 795b2a1..2967e18 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +2005-09-08 Richard Henderson <rth@redhat.com> + + PR debug/23190 + * decl.c (wrapup_globals_for_namespace): Call + emit_debug_global_declarations. + * decl2.c (cp_finish_file): Likewise. + 2005-09-08 Mark Mitchell <mark@codesourcery.com> PR c++/23691 diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 1aa9b8d..50c1fd6 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -789,6 +789,7 @@ wrapup_globals_for_namespace (tree namespace, void* data) if (last_time) { check_global_declarations (vec, len); + emit_debug_global_declarations (vec, len); return 0; } diff --git a/gcc/cp/decl2.c b/gcc/cp/decl2.c index a6e82f0..afb747f 100644 --- a/gcc/cp/decl2.c +++ b/gcc/cp/decl2.c @@ -3106,8 +3106,12 @@ cp_finish_file (void) etc., and emit debugging information. */ walk_namespaces (wrapup_globals_for_namespace, /*data=*/&reconsider); if (VEC_length (tree, pending_statics) != 0) - check_global_declarations (VEC_address (tree, pending_statics), - VEC_length (tree, pending_statics)); + { + check_global_declarations (VEC_address (tree, pending_statics), + VEC_length (tree, pending_statics)); + emit_debug_global_declarations (VEC_address (tree, pending_statics), + VEC_length (tree, pending_statics)); + } /* Generate hidden aliases for Java. */ build_java_method_aliases (); diff --git a/gcc/langhooks.c b/gcc/langhooks.c index 5f3fb4b..d7ed750 100644 --- a/gcc/langhooks.c +++ b/gcc/langhooks.c @@ -478,10 +478,10 @@ write_global_declarations (void) vec[len - i - 1] = decl; wrapup_global_declarations (vec, len); - check_global_declarations (vec, len); + emit_debug_global_declarations (vec, len); - /* Clean up. */ + /* Clean up. */ free (vec); } diff --git a/gcc/passes.c b/gcc/passes.c index 6728e10..86d38cf 100644 --- a/gcc/passes.c +++ b/gcc/passes.c @@ -158,8 +158,7 @@ rest_of_decl_compilation (tree decl, || DECL_INITIAL (decl)) && !DECL_EXTERNAL (decl)) { - if (flag_unit_at_a_time && !cgraph_global_info_ready - && TREE_CODE (decl) != FUNCTION_DECL) + if (TREE_CODE (decl) != FUNCTION_DECL) cgraph_varpool_finalize_decl (decl); else assemble_variable (decl, top_level, at_end, 0); diff --git a/gcc/testsuite/gcc.dg/debug/20050907-1.c b/gcc/testsuite/gcc.dg/debug/20050907-1.c new file mode 100644 index 0000000..0112ff7 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/20050907-1.c @@ -0,0 +1,24 @@ +/* PR 23190 */ +/* Well, collateral damage from a proposed patch fixing 23190. We'd emit + debug info for multilib_exclusions_raw without emitting the variable + itself, leading to link errors. This reduced form is filed as PR 23777, + for not eliminating things soon enough. */ +/* { dg-do link } */ + +static const char *const multilib_exclusions_raw[] = { 0 }; + +void __attribute__((noinline)) f(char *const *p) +{ + __asm__ ("" : : "g"(p) : "memory"); +} + +void g (char **o) +{ + const char *const *q = multilib_exclusions_raw; + + f (o); + while (*q++) + f (o); +} + +int main() { return 0; } diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/var1.c b/gcc/testsuite/gcc.dg/debug/dwarf2/var1.c new file mode 100644 index 0000000..7580450 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/var1.c @@ -0,0 +1,10 @@ +/* PR 23190 */ +/* { dg-do compile } +/* { dg-options "-gdwarf-2 -dA" } */ +/* { dg-final { scan-assembler "xyzzy\[^\\n\\r\]+DW_AT_name" } } */ + +void f(void) +{ + static int xyzzy; + xyzzy += 3; +} diff --git a/gcc/testsuite/gcc.dg/debug/dwarf2/var2.c b/gcc/testsuite/gcc.dg/debug/dwarf2/var2.c new file mode 100644 index 0000000..8ef2a74 --- /dev/null +++ b/gcc/testsuite/gcc.dg/debug/dwarf2/var2.c @@ -0,0 +1,14 @@ +/* PR 23190 */ +/* { dg-do compile } +/* { dg-options "-O2 -gdwarf-2 -dA" } */ +/* { dg-final { scan-assembler "DW_OP_addr\[\\n\\r\]+\[^\\n\\r\]+foo" } } */ +/* { dg-final { scan-assembler "DW_OP_addr\[\\n\\r\]+\[^\\n\\r\]+bar" } } */ + +static int foo; +int bar; +int main(void) +{ + foo += 3; + bar *= 5; + return 0; +} diff --git a/gcc/toplev.c b/gcc/toplev.c index 094a2e2..b963170 100644 --- a/gcc/toplev.c +++ b/gcc/toplev.c @@ -685,177 +685,196 @@ output_file_directive (FILE *asm_file, const char *input_name) #endif } +/* A subroutine of wrapup_global_declarations. We've come to the end of + the compilation unit. All deferred variables should be undeferred, + and all incomplete decls should be finalized. */ + +void +wrapup_global_declaration_1 (tree decl) +{ + /* We're not deferring this any longer. Assignment is conditional to + avoid needlessly dirtying PCH pages. */ + if (CODE_CONTAINS_STRUCT (TREE_CODE (decl), TS_DECL_WITH_VIS) + && DECL_DEFER_OUTPUT (decl) != 0) + DECL_DEFER_OUTPUT (decl) = 0; + + if (TREE_CODE (decl) == VAR_DECL && DECL_SIZE (decl) == 0) + lang_hooks.finish_incomplete_decl (decl); +} + +/* A subroutine of wrapup_global_declarations. Decide whether or not DECL + needs to be output. Return true if it is output. */ + +bool +wrapup_global_declaration_2 (tree decl) +{ + if (TREE_ASM_WRITTEN (decl) || DECL_EXTERNAL (decl)) + return false; + + /* Don't write out static consts, unless we still need them. + + We also keep static consts if not optimizing (for debugging), + unless the user specified -fno-keep-static-consts. + ??? They might be better written into the debug information. + This is possible when using DWARF. + + A language processor that wants static constants to be always + written out (even if it is not used) is responsible for + calling rest_of_decl_compilation itself. E.g. the C front-end + calls rest_of_decl_compilation from finish_decl. + One motivation for this is that is conventional in some + environments to write things like: + static const char rcsid[] = "... version string ..."; + intending to force the string to be in the executable. + + A language processor that would prefer to have unneeded + static constants "optimized away" would just defer writing + them out until here. E.g. C++ does this, because static + constants are often defined in header files. + + ??? A tempting alternative (for both C and C++) would be + to force a constant to be written if and only if it is + defined in a main file, as opposed to an include file. */ + + if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) + { + struct cgraph_varpool_node *node; + bool needed = true; + node = cgraph_varpool_node (decl); + + if (node->finalized) + needed = false; + else if (node->alias) + needed = false; + else if (!cgraph_global_info_ready + && (TREE_USED (decl) + || TREE_USED (DECL_ASSEMBLER_NAME (decl)))) + /* needed */; + else if (node->needed) + /* needed */; + else if (DECL_COMDAT (decl)) + needed = false; + else if (TREE_READONLY (decl) && !TREE_PUBLIC (decl) + && (optimize || !flag_keep_static_consts + || DECL_ARTIFICIAL (decl))) + needed = false; + + if (needed) + { + rest_of_decl_compilation (decl, 1, 1); + return true; + } + } + + return false; +} + /* Do any final processing required for the declarations in VEC, of which there are LEN. We write out inline functions and variables that have been deferred until this point, but which are required. Returns nonzero if anything was put out. */ -int +bool wrapup_global_declarations (tree *vec, int len) { - tree decl; + bool reconsider, output_something = false; int i; - int reconsider; - int output_something = 0; for (i = 0; i < len; i++) - { - decl = vec[i]; - - /* We're not deferring this any longer. Assignment is - conditional to avoid needlessly dirtying PCH pages. */ - if (CODE_CONTAINS_STRUCT (TREE_CODE (decl), TS_DECL_WITH_VIS) - && DECL_DEFER_OUTPUT (decl) != 0) - DECL_DEFER_OUTPUT (decl) = 0; - - if (TREE_CODE (decl) == VAR_DECL && DECL_SIZE (decl) == 0) - lang_hooks.finish_incomplete_decl (decl); - } + wrapup_global_declaration_1 (vec[i]); /* Now emit any global variables or functions that we have been putting off. We need to loop in case one of the things emitted here references another one which comes earlier in the list. */ do { - reconsider = 0; + reconsider = false; for (i = 0; i < len; i++) - { - decl = vec[i]; - - if (TREE_ASM_WRITTEN (decl) || DECL_EXTERNAL (decl)) - continue; - - /* Don't write out static consts, unless we still need them. - - We also keep static consts if not optimizing (for debugging), - unless the user specified -fno-keep-static-consts. - ??? They might be better written into the debug information. - This is possible when using DWARF. - - A language processor that wants static constants to be always - written out (even if it is not used) is responsible for - calling rest_of_decl_compilation itself. E.g. the C front-end - calls rest_of_decl_compilation from finish_decl. - One motivation for this is that is conventional in some - environments to write things like: - static const char rcsid[] = "... version string ..."; - intending to force the string to be in the executable. - - A language processor that would prefer to have unneeded - static constants "optimized away" would just defer writing - them out until here. E.g. C++ does this, because static - constants are often defined in header files. - - ??? A tempting alternative (for both C and C++) would be - to force a constant to be written if and only if it is - defined in a main file, as opposed to an include file. */ - - if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)) - { - struct cgraph_varpool_node *node; - bool needed = 1; - node = cgraph_varpool_node (decl); - - if (node->finalized) - needed = 0; - else if (node->alias) - needed = 0; - else if (!cgraph_global_info_ready - && (TREE_USED (decl) - || TREE_USED (DECL_ASSEMBLER_NAME (decl)))) - /* needed */; - else if (node->needed) - /* needed */; - else if (DECL_COMDAT (decl)) - needed = 0; - else if (TREE_READONLY (decl) && !TREE_PUBLIC (decl) - && (optimize || !flag_keep_static_consts - || DECL_ARTIFICIAL (decl))) - needed = 0; - - if (needed) - { - reconsider = 1; - rest_of_decl_compilation (decl, 1, 1); - } - } - } - + reconsider |= wrapup_global_declaration_2 (vec[i]); if (reconsider) - output_something = 1; + output_something = true; } while (reconsider); return output_something; } +/* A subroutine of check_global_declarations. Issue appropriate warnings + for the global declaration DECL. */ + +void +check_global_declaration_1 (tree decl) +{ + /* Warn about any function declared static but not defined. We don't + warn about variables, because many programs have static variables + that exist only to get some text into the object file. */ + if (TREE_CODE (decl) == FUNCTION_DECL + && DECL_INITIAL (decl) == 0 + && DECL_EXTERNAL (decl) + && ! DECL_ARTIFICIAL (decl) + && ! TREE_NO_WARNING (decl) + && ! TREE_PUBLIC (decl) + && (warn_unused_function + || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) + { + if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) + pedwarn ("%q+F used but never defined", decl); + else + warning (0, "%q+F declared %<static%> but never defined", decl); + /* This symbol is effectively an "extern" declaration now. */ + TREE_PUBLIC (decl) = 1; + assemble_external (decl); + } + + /* Warn about static fns or vars defined but not used. */ + if (((warn_unused_function && TREE_CODE (decl) == FUNCTION_DECL) + /* We don't warn about "static const" variables because the + "rcs_id" idiom uses that construction. */ + || (warn_unused_variable + && TREE_CODE (decl) == VAR_DECL && ! TREE_READONLY (decl))) + && ! DECL_IN_SYSTEM_HEADER (decl) + && ! TREE_USED (decl) + /* The TREE_USED bit for file-scope decls is kept in the identifier, + to handle multiple external decls in different scopes. */ + && ! TREE_USED (DECL_NAME (decl)) + && ! DECL_EXTERNAL (decl) + && ! TREE_PUBLIC (decl) + /* A volatile variable might be used in some non-obvious way. */ + && ! TREE_THIS_VOLATILE (decl) + /* Global register variables must be declared to reserve them. */ + && ! (TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)) + /* Otherwise, ask the language. */ + && lang_hooks.decls.warn_unused_global (decl)) + warning (0, "%q+D defined but not used", decl); +} + /* Issue appropriate warnings for the global declarations in VEC (of - which there are LEN). Output debugging information for them. */ + which there are LEN). */ void check_global_declarations (tree *vec, int len) { - tree decl; int i; for (i = 0; i < len; i++) - { - decl = vec[i]; - - /* Warn about any function - declared static but not defined. - We don't warn about variables, - because many programs have static variables - that exist only to get some text into the object file. */ - if (TREE_CODE (decl) == FUNCTION_DECL - && DECL_INITIAL (decl) == 0 - && DECL_EXTERNAL (decl) - && ! DECL_ARTIFICIAL (decl) - && ! TREE_NO_WARNING (decl) - && ! TREE_PUBLIC (decl) - && (warn_unused_function - || TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))) - { - if (TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl))) - pedwarn ("%q+F used but never defined", decl); - else - warning (0, "%q+F declared %<static%> but never defined", - decl); - /* This symbol is effectively an "extern" declaration now. */ - TREE_PUBLIC (decl) = 1; - assemble_external (decl); - } + check_global_declaration_1 (vec[i]); +} - /* Warn about static fns or vars defined but not used. */ - if (((warn_unused_function && TREE_CODE (decl) == FUNCTION_DECL) - /* We don't warn about "static const" variables because the - "rcs_id" idiom uses that construction. */ - || (warn_unused_variable - && TREE_CODE (decl) == VAR_DECL && ! TREE_READONLY (decl))) - && ! DECL_IN_SYSTEM_HEADER (decl) - && ! TREE_USED (decl) - /* The TREE_USED bit for file-scope decls is kept in the identifier, - to handle multiple external decls in different scopes. */ - && ! TREE_USED (DECL_NAME (decl)) - && ! DECL_EXTERNAL (decl) - && ! TREE_PUBLIC (decl) - /* A volatile variable might be used in some non-obvious way. */ - && ! TREE_THIS_VOLATILE (decl) - /* Global register variables must be declared to reserve them. */ - && ! (TREE_CODE (decl) == VAR_DECL && DECL_REGISTER (decl)) - /* Otherwise, ask the language. */ - && lang_hooks.decls.warn_unused_global (decl)) - warning (0, "%q+D defined but not used", decl); - - /* Avoid confusing the debug information machinery when there are - errors. */ - if (errorcount == 0 && sorrycount == 0) - { - timevar_push (TV_SYMOUT); - (*debug_hooks->global_decl) (decl); - timevar_pop (TV_SYMOUT); - } - } +/* Emit debugging information for all global declarations in VEC. */ + +void +emit_debug_global_declarations (tree *vec, int len) +{ + int i; + + /* Avoid confusing the debug information machinery when there are errors. */ + if (errorcount != 0 || sorrycount != 0) + return; + + timevar_push (TV_SYMOUT); + for (i = 0; i < len; i++) + debug_hooks->global_decl (vec[i]); + timevar_pop (TV_SYMOUT); } /* Warn about a use of an identifier which was marked deprecated. */ diff --git a/gcc/toplev.h b/gcc/toplev.h index e293c9e..35d53eb 100644 --- a/gcc/toplev.h +++ b/gcc/toplev.h @@ -92,8 +92,12 @@ extern void fnotice (FILE *, const char *, ...) ATTRIBUTE_PRINTF_2; #endif -extern int wrapup_global_declarations (tree *, int); +extern void wrapup_global_declaration_1 (tree); +extern bool wrapup_global_declaration_2 (tree); +extern bool wrapup_global_declarations (tree *, int); +extern void check_global_declaration_1 (tree); extern void check_global_declarations (tree *, int); +extern void emit_debug_global_declarations (tree *, int); extern void write_global_declarations (void); /* A unique local time stamp, might be zero if none is available. */ |