Commit b646ba3f by Dodji Seketeli Committed by Dodji Seketeli

re PR debug/41065 (DW_TAG_enumeration_type+DW_TAG_enumerator is sometimes missing)

Fix PR debug/41065

gcc/ChangeLog:
	PR debug/41065
	* function.h (types_used_by_vars_hash): Declare new hash table.
	(types_used_by_vars_eq, types_used_by_var_decl_insert): Declare
	equality and hash function for the hash table.
	(types_used_by_cur_var_decl): Declare a new global chained list.
	(types_used_by_var_decl_insert): Declare new function.
	* function.c (types_used_by_vars_hash): Define the hashtable ...
	(types_used_by_vars_eq, types_used_by_vars_do_hash): ... as well as
	its equality and hash functions.
	(hash_types_used_by_vars_entry): New hash helper.
	(types_used_by_cur_var_decl): Define the global chained list.
	(used_types_insert): Update the list of types used by the global
	variable being parsed.
	(types_used_by_var_decl_insert): Define new function.
	* c-common.h (record_types_used_by_current_var_decl): Declare ...
	* c-common.c (record_types_used_by_current_var_decl): ... new
	function.
	* c-decl.c (finish_decl): Record the types used by the global
	variable declaration we've just parsed.
	* dwarf2out.c (premark_used_types): Insert a new line between
	comment and function.
	(premark_used_types_helper): Fix comment.
	(premark_types_used_by_global_vars_helper,
	premark_types_used_by_global_vars): New functions.
	(prune_unused_types): Do not prune types used by global variables.

gcc/cp/ChangeLog:
	PR debug/41065
	* decl.c (cp_finish_decl): Record the types used by the global
	variable declaration we've just parsed.

gcc/testsuite/ChangeLog:
	PR debug/41065
	* gcc.dg/debug/dwarf2/global-used-types.c: New test.

From-SVN: r152085
parent 4c685825
...@@ -9182,6 +9182,31 @@ is_typedef_decl (tree x) ...@@ -9182,6 +9182,31 @@ is_typedef_decl (tree x)
&& DECL_ORIGINAL_TYPE (x) != NULL_TREE); && DECL_ORIGINAL_TYPE (x) != NULL_TREE);
} }
/* Record the types used by the current global variable declaration
being parsed, so that we can decide later to emit their debug info.
Those types are in types_used_by_cur_var_decl, and we are going to
store them in the types_used_by_vars_hash hash table.
DECL is the declaration of the global variable that has been parsed. */
void
record_types_used_by_current_var_decl (tree decl)
{
gcc_assert (decl && DECL_P (decl) && TREE_STATIC (decl));
if (types_used_by_cur_var_decl)
{
tree node;
for (node = types_used_by_cur_var_decl;
node;
node = TREE_CHAIN (node))
{
tree type = TREE_PURPOSE (node);
types_used_by_var_decl_insert (type, decl);
}
types_used_by_cur_var_decl = NULL;
}
}
/* The C and C++ parsers both use vectors to hold function arguments. /* The C and C++ parsers both use vectors to hold function arguments.
For efficiency, we keep a cache of unused vectors. This is the For efficiency, we keep a cache of unused vectors. This is the
cache. */ cache. */
......
...@@ -1130,6 +1130,7 @@ extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree); ...@@ -1130,6 +1130,7 @@ extern enum omp_clause_default_kind c_omp_predetermined_sharing (tree);
/* Not in c-omp.c; provided by the front end. */ /* Not in c-omp.c; provided by the front end. */
extern bool c_omp_sharing_predetermined (tree); extern bool c_omp_sharing_predetermined (tree);
extern tree c_omp_remap_decl (tree, bool); extern tree c_omp_remap_decl (tree, bool);
extern void record_types_used_by_current_var_decl (tree);
/* In order for the format checking to accept the C frontend /* In order for the format checking to accept the C frontend
diagnostic framework extensions, you must include this file before diagnostic framework extensions, you must include this file before
......
...@@ -4064,6 +4064,13 @@ finish_decl (tree decl, location_t init_loc, tree init, ...@@ -4064,6 +4064,13 @@ finish_decl (tree decl, location_t init_loc, tree init,
if (asmspec_tree) if (asmspec_tree)
asmspec = TREE_STRING_POINTER (asmspec_tree); asmspec = TREE_STRING_POINTER (asmspec_tree);
if (TREE_CODE (decl) == VAR_DECL
&& TREE_STATIC (decl)
&& global_bindings_p ())
/* So decl is a global variable. Record the types it uses
so that we can decide later to emit debug info for them. */
record_types_used_by_current_var_decl (decl);
/* If `start_decl' didn't like having an initialization, ignore it now. */ /* If `start_decl' didn't like having an initialization, ignore it now. */
if (init != 0 && DECL_INITIAL (decl) == 0) if (init != 0 && DECL_INITIAL (decl) == 0)
init = 0; init = 0;
......
2009-09-23 Dodji Seketeli <dodji@redhat.com>
PR debug/41065
* decl.c (cp_finish_decl): Record the types used by the global
variable declaration we've just parsed.
2009-09-22 Dodji Seketeli <dodji@redhat.com> 2009-09-22 Dodji Seketeli <dodji@redhat.com>
* cp-lang.c (LANG_HOOKS_FUNCTION_PARAMETER_PACK_P, * cp-lang.c (LANG_HOOKS_FUNCTION_PARAMETER_PACK_P,
......
...@@ -5801,6 +5801,15 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p, ...@@ -5801,6 +5801,15 @@ cp_finish_decl (tree decl, tree init, bool init_const_expr_p,
type. */ type. */
else if (TREE_CODE (type) == ARRAY_TYPE) else if (TREE_CODE (type) == ARRAY_TYPE)
layout_type (type); layout_type (type);
if (!processing_template_decl
&& TREE_STATIC (decl)
&& !at_function_scope_p ()
&& current_function_decl == NULL)
/* So decl is a global variable or a static member of a
non local class. Record the types it uses
so that we can decide later to emit debug info for them. */
record_types_used_by_current_var_decl (decl);
} }
else if (TREE_CODE (decl) == FIELD_DECL else if (TREE_CODE (decl) == FIELD_DECL
&& TYPE_FOR_JAVA (type) && MAYBE_CLASS_TYPE_P (type)) && TYPE_FOR_JAVA (type) && MAYBE_CLASS_TYPE_P (type))
......
...@@ -15649,10 +15649,11 @@ dwarf2out_abstract_function (tree decl) ...@@ -15649,10 +15649,11 @@ dwarf2out_abstract_function (tree decl)
} }
/* Helper function of premark_used_types() which gets called through /* Helper function of premark_used_types() which gets called through
htab_traverse_resize(). htab_traverse.
Marks the DIE of a given type in *SLOT as perennial, so it never gets Marks the DIE of a given type in *SLOT as perennial, so it never gets
marked as unused by prune_unused_types. */ marked as unused by prune_unused_types. */
static int static int
premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED) premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
{ {
...@@ -15666,7 +15667,42 @@ premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED) ...@@ -15666,7 +15667,42 @@ premark_used_types_helper (void **slot, void *data ATTRIBUTE_UNUSED)
return 1; return 1;
} }
/* Helper function of premark_types_used_by_global_vars which gets called
through htab_traverse.
Marks the DIE of a given type in *SLOT as perennial, so it never gets
marked as unused by prune_unused_types. The DIE of the type is marked
only if the global variable using the type will actually be emitted. */
static int
premark_types_used_by_global_vars_helper (void **slot,
void *data ATTRIBUTE_UNUSED)
{
struct types_used_by_vars_entry *entry;
dw_die_ref die;
entry = (struct types_used_by_vars_entry *) *slot;
gcc_assert (entry->type != NULL
&& entry->var_decl != NULL);
die = lookup_type_die (entry->type);
if (die)
{
/* Ask cgraph if the global variable really is to be emitted.
If yes, then we'll keep the DIE of ENTRY->TYPE. */
struct varpool_node *node = varpool_node (entry->var_decl);
if (node->needed)
{
die->die_perennial_p = 1;
/* Keep the parent DIEs as well. */
while ((die = die->die_parent) && die->die_perennial_p == 0)
die->die_perennial_p = 1;
}
}
return 1;
}
/* Mark all members of used_types_hash as perennial. */ /* Mark all members of used_types_hash as perennial. */
static void static void
premark_used_types (void) premark_used_types (void)
{ {
...@@ -15674,6 +15710,16 @@ premark_used_types (void) ...@@ -15674,6 +15710,16 @@ premark_used_types (void)
htab_traverse (cfun->used_types_hash, premark_used_types_helper, NULL); htab_traverse (cfun->used_types_hash, premark_used_types_helper, NULL);
} }
/* Mark all members of types_used_by_vars_entry as perennial. */
static void
premark_types_used_by_global_vars (void)
{
if (types_used_by_vars_hash)
htab_traverse (types_used_by_vars_hash,
premark_types_used_by_global_vars_helper, NULL);
}
/* Generate a DIE to represent a declared function (either file-scope or /* Generate a DIE to represent a declared function (either file-scope or
block-local). */ block-local). */
...@@ -18776,6 +18822,9 @@ prune_unused_types (void) ...@@ -18776,6 +18822,9 @@ prune_unused_types (void)
verify_marks_clear (node->die); verify_marks_clear (node->die);
#endif /* ENABLE_ASSERT_CHECKING */ #endif /* ENABLE_ASSERT_CHECKING */
/* Mark types that are used in global variables. */
premark_types_used_by_global_vars ();
/* Set the mark on nodes that are actually used. */ /* Set the mark on nodes that are actually used. */
prune_unused_types_walk (comp_unit_die); prune_unused_types_walk (comp_unit_die);
for (node = limbo_die_list; node; node = node->next) for (node = limbo_die_list; node; node = node->next)
......
...@@ -130,6 +130,10 @@ static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def))) ...@@ -130,6 +130,10 @@ static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def))) static GTY((if_marked ("ggc_marked_p"), param_is (struct rtx_def)))
htab_t epilogue_insn_hash; htab_t epilogue_insn_hash;
htab_t types_used_by_vars_hash = NULL;
tree types_used_by_cur_var_decl = NULL;
/* Forward declarations. */ /* Forward declarations. */
static struct temp_slot *find_temp_slot_from_address (rtx); static struct temp_slot *find_temp_slot_from_address (rtx);
...@@ -5426,6 +5430,7 @@ rest_of_handle_check_leaf_regs (void) ...@@ -5426,6 +5430,7 @@ rest_of_handle_check_leaf_regs (void)
} }
/* Insert a TYPE into the used types hash table of CFUN. */ /* Insert a TYPE into the used types hash table of CFUN. */
static void static void
used_types_insert_helper (tree type, struct function *func) used_types_insert_helper (tree type, struct function *func)
{ {
...@@ -5450,7 +5455,81 @@ used_types_insert (tree t) ...@@ -5450,7 +5455,81 @@ used_types_insert (tree t)
t = TREE_TYPE (t); t = TREE_TYPE (t);
t = TYPE_MAIN_VARIANT (t); t = TYPE_MAIN_VARIANT (t);
if (debug_info_level > DINFO_LEVEL_NONE) if (debug_info_level > DINFO_LEVEL_NONE)
used_types_insert_helper (t, cfun); {
if (cfun)
used_types_insert_helper (t, cfun);
else
/* So this might be a type referenced by a global variable.
Record that type so that we can later decide to emit its debug
information. */
types_used_by_cur_var_decl =
tree_cons (t, NULL, types_used_by_cur_var_decl);
}
}
/* Helper to Hash a struct types_used_by_vars_entry. */
static hashval_t
hash_types_used_by_vars_entry (const struct types_used_by_vars_entry *entry)
{
gcc_assert (entry && entry->var_decl && entry->type);
return iterative_hash_object (entry->type,
iterative_hash_object (entry->var_decl, 0));
}
/* Hash function of the types_used_by_vars_entry hash table. */
hashval_t
types_used_by_vars_do_hash (const void *x)
{
const struct types_used_by_vars_entry *entry =
(const struct types_used_by_vars_entry *) x;
return hash_types_used_by_vars_entry (entry);
}
/*Equality function of the types_used_by_vars_entry hash table. */
int
types_used_by_vars_eq (const void *x1, const void *x2)
{
const struct types_used_by_vars_entry *e1 =
(const struct types_used_by_vars_entry *) x1;
const struct types_used_by_vars_entry *e2 =
(const struct types_used_by_vars_entry *)x2;
return (e1->var_decl == e2->var_decl && e1->type == e2->type);
}
/* Inserts an entry into the types_used_by_vars_hash hash table. */
void
types_used_by_var_decl_insert (tree type, tree var_decl)
{
if (type != NULL && var_decl != NULL)
{
void **slot;
struct types_used_by_vars_entry e;
e.var_decl = var_decl;
e.type = type;
if (types_used_by_vars_hash == NULL)
types_used_by_vars_hash =
htab_create_ggc (37, types_used_by_vars_do_hash,
types_used_by_vars_eq, NULL);
slot = htab_find_slot_with_hash (types_used_by_vars_hash, &e,
hash_types_used_by_vars_entry (&e), INSERT);
if (*slot == NULL)
{
struct types_used_by_vars_entry *entry;
entry = (struct types_used_by_vars_entry*) ggc_alloc
(sizeof (struct types_used_by_vars_entry));
entry->type = type;
entry->var_decl = var_decl;
*slot = entry;
}
}
} }
struct rtl_opt_pass pass_leaf_regs = struct rtl_opt_pass pass_leaf_regs =
......
...@@ -622,6 +622,28 @@ extern int virtuals_instantiated; ...@@ -622,6 +622,28 @@ extern int virtuals_instantiated;
/* Nonzero if at least one trampoline has been created. */ /* Nonzero if at least one trampoline has been created. */
extern int trampolines_created; extern int trampolines_created;
struct GTY(()) types_used_by_vars_entry {
tree type;
tree var_decl;
};
/* Hash table making the relationship between a global variable
and the types it references in its initializer. The key of the
entry is a referenced type, and the value is the DECL of the global
variable. types_use_by_vars_do_hash and types_used_by_vars_eq below are
the hash and equality functions to use for this hash table. */
extern GTY((param_is (struct types_used_by_vars_entry))) htab_t
types_used_by_vars_hash;
hashval_t types_used_by_vars_do_hash (const void*);
int types_used_by_vars_eq (const void *, const void *);
void types_used_by_var_decl_insert (tree type, tree var_decl);
/* During parsing of a global variable, this linked list points to
the list of types referenced by the global variable. */
extern GTY(()) tree types_used_by_cur_var_decl;
/* cfun shouldn't be set directly; use one of these functions instead. */ /* cfun shouldn't be set directly; use one of these functions instead. */
extern void set_cfun (struct function *new_cfun); extern void set_cfun (struct function *new_cfun);
extern void push_cfun (struct function *new_cfun); extern void push_cfun (struct function *new_cfun);
......
2009-09-23 Dodji Seketeli <dodji@redhat.com>
PR debug/41065
* gcc.dg/debug/dwarf2/global-used-types.c: New test.
2009-09-23 Andreas Schwab <schwab@redhat.com> 2009-09-23 Andreas Schwab <schwab@redhat.com>
* lib/profopt.exp (profopt-get-options): Set tool_flags for * lib/profopt.exp (profopt-get-options): Set tool_flags for
......
// Contributed by Dodji Seketeli <dodji@redhat.com>
// { dg-options "-g -dA -fno-merge-debug-strings" }
// { dg-do compile }
// { dg-final { scan-assembler-times "DIE \\(0x.*?\\) DW_TAG_enumeration_type" 1 } }
// { dg-final { scan-assembler-times "DIE \\(0x.*?\\) DW_TAG_enumerator" 2 } }
// { dg-final { scan-assembler-times "ascii \"a.0\"\[\t \]+.*?DW_AT_name" 1 } }
// { dg-final { scan-assembler-times "ascii \"b.0\"\[\t \]+.*?DW_AT_name" 1 } }
struct foo
{
enum { a, b };
};
char s[foo::b];
/*
Contributed by Dodji Seketeli <dodji@redhat.com>
{ dg-options "-g -dA -fno-merge-debug-strings" }
{ dg-do compile }
{ dg-final { scan-assembler-times "DIE \\(0x.*?\\) DW_TAG_enumeration_type" 1 } }
{ dg-final { scan-assembler-times "DIE \\(0x.*?\\) DW_TAG_enumerator" 2 } }
{ dg-final { scan-assembler-times "ascii \"a.0\"\[\t \]+.*?DW_AT_name" 1 } }
{ dg-final { scan-assembler-times "ascii \"b.0\"\[\t \]+.*?DW_AT_name" 1 } }
*/
enum { a, b };
int v = a;
char s[b];
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment