This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [patch 10/10] debug-early merge: compiler proper
- From: Aldy Hernandez <aldyh at redhat dot com>
- To: Richard Biener <richard dot guenther at gmail dot com>
- Cc: Jason Merrill <jason at redhat dot com>, Jan Hubicka <hubicka at ucw dot cz>, gcc-patches <gcc-patches at gcc dot gnu dot org>
- Date: Tue, 02 Jun 2015 14:21:08 -0400
- Subject: Re: [patch 10/10] debug-early merge: compiler proper
- Authentication-results: sourceware.org; auth=none
- References: <554C060F dot 6000609 at redhat dot com> <CAFiYyc16u2na9VeyMb5cVf4cH=caiBy6PRTJkX9DndzHcFxkBQ at mail dot gmail dot com> <555CAD35 dot 5040304 at redhat dot com> <5565BB13 dot 6040205 at redhat dot com> <5567643C dot 1020306 at redhat dot com> <55677C05 dot 6040302 at redhat dot com> <5568B32A dot 1010100 at redhat dot com> <78B564EA-B9C4-4351-BFD0-9C78EA4C2528 at gmail dot com> <5568BF0A dot 7070903 at redhat dot com> <556A5B43 dot 7050105 at redhat dot com> <556B7132 dot 7010504 at redhat dot com> <CAFiYyc3MJpB5vfbCzZgYmO3OwnO6Gn=wLw9MJsQYNwo_mirFtg at mail dot gmail dot com> <CAFiYyc3FKVgko0-ozdHropratHfmbAoDYqT_1TqmOCDvVDN2_g at mail dot gmail dot com> <556C7D81 dot 30504 at redhat dot com> <74C942F9-D13A-4843-8760-24D2314D6386 at gmail dot com> <556C998D dot 2050209 at redhat dot com> <CAFiYyc3o5XxEmnzrboCrXdMAStAiySsVUcnKJqsG_NzesJ7riA at mail dot gmail dot com>
On 06/02/2015 04:11 AM, Richard Biener wrote:
I suppose we can change things this way as a followup (as it needs some work)
Ok.
I cleaned things up using variably_modified_type_p() as you did, instead
of the INTEGER_CST nonsense. Attached are the latest dwarf2out.c
changes against mainline.
Jason are you ok with the attached wrt VLAs? If so, I'm putting this
aside while I work on DECL_ABSTRACT and friends, and hopefully wrap
things up.
Tested on x86-64 Linux, gcc and gdb testsuites.
Thanks guys.
Aldy
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 15c545e..62b06c4 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -1268,16 +1268,6 @@ struct GTY((for_user)) dwarf_file_data {
int emitted_number;
};
-typedef struct GTY(()) deferred_locations_struct
-{
- tree variable;
- dw_die_ref die;
-} deferred_locations;
-
-
-static GTY(()) vec<deferred_locations, va_gc> *deferred_locations_list;
-
-
/* Describe an entry into the .debug_addr section. */
enum ate_kind {
@@ -2448,6 +2438,7 @@ build_cfa_aligned_loc (dw_cfa_location *cfa,
static void dwarf2out_init (const char *);
static void dwarf2out_finish (const char *);
+static void dwarf2out_early_finish (void);
static void dwarf2out_assembly_start (void);
static void dwarf2out_define (unsigned int, const char *);
static void dwarf2out_undef (unsigned int, const char *);
@@ -2457,7 +2448,8 @@ static void dwarf2out_function_decl (tree);
static void dwarf2out_begin_block (unsigned, unsigned);
static void dwarf2out_end_block (unsigned, unsigned);
static bool dwarf2out_ignore_block (const_tree);
-static void dwarf2out_global_decl (tree);
+static void dwarf2out_early_global_decl (tree);
+static void dwarf2out_late_global_decl (tree);
static void dwarf2out_type_decl (tree, int);
static void dwarf2out_imported_module_or_decl (tree, tree, tree, bool);
static void dwarf2out_imported_module_or_decl_1 (tree, tree, tree,
@@ -2474,6 +2466,7 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
{
dwarf2out_init,
dwarf2out_finish,
+ dwarf2out_early_finish,
dwarf2out_assembly_start,
dwarf2out_define,
dwarf2out_undef,
@@ -2495,7 +2488,8 @@ const struct gcc_debug_hooks dwarf2_debug_hooks =
dwarf2out_begin_function,
dwarf2out_end_function, /* end_function */
dwarf2out_function_decl, /* function_decl */
- dwarf2out_global_decl,
+ dwarf2out_early_global_decl,
+ dwarf2out_late_global_decl,
dwarf2out_type_decl, /* type_decl */
dwarf2out_imported_module_or_decl,
debug_nothing_tree, /* deferred_inline_function */
@@ -2636,10 +2630,20 @@ typedef struct GTY((chain_circular ("%h.die_sib"), for_user)) die_struct {
/* Die is used and must not be pruned as unused. */
BOOL_BITFIELD die_perennial_p : 1;
BOOL_BITFIELD comdat_type_p : 1; /* DIE has a type signature */
+ /* Die was generated early via dwarf2out_early_global_decl. */
+ BOOL_BITFIELD dumped_early : 1;
/* Lots of spare bits. */
}
die_node;
+/* Set to TRUE while dwarf2out_early_global_decl is running. */
+static bool early_dwarf;
+struct set_early_dwarf {
+ bool saved;
+ set_early_dwarf () : saved(early_dwarf) { early_dwarf = true; }
+ ~set_early_dwarf () { early_dwarf = saved; }
+};
+
/* Evaluate 'expr' while 'c' is set to each child of DIE in order. */
#define FOR_EACH_CHILD(die, c, expr) do { \
c = die->die_child; \
@@ -2690,9 +2694,13 @@ typedef struct GTY(()) comdat_type_struct
}
comdat_type_node;
-/* The limbo die list structure. */
+/* A list of DIEs for which we can't determine ancestry (parent_die
+ field) just yet. Later in dwarf2out_finish we will fill in the
+ missing bits. */
typedef struct GTY(()) limbo_die_struct {
dw_die_ref die;
+ /* The tree for which this DIE was created for. We use this to
+ determine ancestry later. */
tree created_for;
struct limbo_die_struct *next;
}
@@ -2939,7 +2947,7 @@ static GTY((length ("abbrev_die_table_allocated")))
/* Number of elements currently allocated for abbrev_die_table. */
static GTY(()) unsigned abbrev_die_table_allocated;
-/* Number of elements in type_die_table currently in use. */
+/* Number of elements in abbrev_die_table currently in use. */
static GTY(()) unsigned abbrev_die_table_in_use;
/* Size (in elements) of increments by which we may expand the
@@ -3021,9 +3029,6 @@ static GTY(()) struct dwarf_file_data * last_emitted_file;
/* Number of internal labels generated by gen_internal_sym(). */
static GTY(()) int label_num;
-/* Cached result of previous call to lookup_filename. */
-static GTY(()) struct dwarf_file_data * file_table_last_lookup;
-
static GTY(()) vec<die_arg_entry, va_gc> *tmpl_value_parm_die_table;
/* Instances of generic types for which we need to generate debug
@@ -3108,7 +3113,7 @@ static inline dw_die_ref get_AT_ref (dw_die_ref, enum dwarf_attribute);
static bool is_cxx (void);
static bool is_fortran (void);
static bool is_ada (void);
-static void remove_AT (dw_die_ref, enum dwarf_attribute);
+static bool remove_AT (dw_die_ref, enum dwarf_attribute);
static void remove_child_TAG (dw_die_ref, enum dwarf_tag);
static void add_child_die (dw_die_ref, dw_die_ref);
static dw_die_ref new_die (enum dwarf_tag, dw_die_ref, tree);
@@ -4748,16 +4753,17 @@ is_ada (void)
return lang == DW_LANG_Ada95 || lang == DW_LANG_Ada83;
}
-/* Remove the specified attribute if present. */
+/* Remove the specified attribute if present. Return TRUE if removal
+ was successful. */
-static void
+static bool
remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
{
dw_attr_ref a;
unsigned ix;
if (! die)
- return;
+ return false;
FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
if (a->dw_attr == attr_kind)
@@ -4769,8 +4775,9 @@ remove_AT (dw_die_ref die, enum dwarf_attribute attr_kind)
/* vec::ordered_remove should help reduce the number of abbrevs
that are needed. */
die->die_attr->ordered_remove (ix);
- return;
+ return true;
}
+ return false;
}
/* Remove CHILD from its parent. PREV must have the property that
@@ -4844,6 +4851,7 @@ remove_child_TAG (dw_die_ref die, enum dwarf_tag tag)
while (c->die_tag == tag)
{
remove_child_with_prev (c, prev);
+ c->die_parent = NULL;
/* Might have removed every child. */
if (c == c->die_sib)
return;
@@ -4873,6 +4881,21 @@ add_child_die (dw_die_ref die, dw_die_ref child_die)
die->die_child = child_die;
}
+/* Unassociate CHILD from its parent, and make its parent be
+ NEW_PARENT. */
+
+static void
+reparent_child (dw_die_ref child, dw_die_ref new_parent)
+{
+ for (dw_die_ref p = child->die_parent->die_child; ; p = p->die_sib)
+ if (p->die_sib == child)
+ {
+ remove_child_with_prev (child, p);
+ break;
+ }
+ add_child_die (new_parent, child);
+}
+
/* Move CHILD, which must be a child of PARENT or the DIE for which PARENT
is the specification, to the end of PARENT's list of children.
This is done by removing and re-adding it. */
@@ -4880,8 +4903,6 @@ add_child_die (dw_die_ref die, dw_die_ref child_die)
static void
splice_child_die (dw_die_ref parent, dw_die_ref child)
{
- dw_die_ref p;
-
/* We want the declaration DIE from inside the class, not the
specification DIE at toplevel. */
if (child->die_parent != parent)
@@ -4896,17 +4917,13 @@ splice_child_die (dw_die_ref parent, dw_die_ref child)
|| (child->die_parent
== get_AT_ref (parent, DW_AT_specification)));
- for (p = child->die_parent->die_child; ; p = p->die_sib)
- if (p->die_sib == child)
- {
- remove_child_with_prev (child, p);
- break;
- }
-
- add_child_die (parent, child);
+ reparent_child (child, parent);
}
-/* Return a pointer to a newly created DIE node. */
+/* Create and return a new die with a parent of PARENT_DIE. If
+ PARENT_DIE is NULL, the new DIE is placed in limbo and an
+ associated tree T must be supplied to determine parenthood
+ later. */
static inline dw_die_ref
new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
@@ -4915,12 +4932,44 @@ new_die (enum dwarf_tag tag_value, dw_die_ref parent_die, tree t)
die->die_tag = tag_value;
+ if (early_dwarf)
+ die->dumped_early = true;
+
if (parent_die != NULL)
add_child_die (parent_die, die);
else
{
limbo_die_node *limbo_node;
+ /* No DIEs created after early dwarf should end up in limbo,
+ because the limbo list should not persist past LTO
+ streaming. */
+ if (tag_value != DW_TAG_compile_unit
+ /* These are allowed because they're generated while
+ breaking out COMDAT units late. */
+ && tag_value != DW_TAG_type_unit
+ && !early_dwarf
+ /* Allow nested functions to live in limbo because they will
+ only temporarily live there, as decls_for_scope will fix
+ them up. */
+ && (TREE_CODE (t) != FUNCTION_DECL
+ || !decl_function_context (t))
+ /* Same as nested functions above but for types. Types that
+ are local to a function will be fixed in
+ decls_for_scope. */
+ && (!RECORD_OR_UNION_TYPE_P (t)
+ || !TYPE_CONTEXT (t)
+ || TREE_CODE (TYPE_CONTEXT (t)) != FUNCTION_DECL)
+ /* FIXME debug-early: Allow late limbo DIE creation for LTO,
+ especially in the ltrans stage, but once we implement LTO
+ dwarf streaming, we should remove this exception. */
+ && !in_lto_p)
+ {
+ fprintf (stderr, "symbol ended up in limbo too late:");
+ debug_generic_stmt (t);
+ gcc_unreachable ();
+ }
+
limbo_node = ggc_cleared_alloc<limbo_die_node> ();
limbo_node->die = die;
limbo_node->created_for = t;
@@ -5576,9 +5625,18 @@ print_die (dw_die_ref die, FILE *outfile)
unsigned ix;
print_spaces (outfile);
- fprintf (outfile, "DIE %4ld: %s (%p)\n",
+ fprintf (outfile, "DIE %4ld: %s (%p)",
die->die_offset, dwarf_tag_name (die->die_tag),
(void*) die);
+ if (die->dumped_early)
+ {
+ fprintf (outfile, " (DUMPED EARLY");
+ const char *name = get_AT_string (die, DW_AT_name);
+ if (name)
+ fprintf (outfile, ": %s", name);
+ fputc (')', outfile);
+ }
+ fputc ('\n', outfile);
print_spaces (outfile);
fprintf (outfile, " abbrev id: %lu", die->die_abbrev);
fprintf (outfile, " offset: %ld", die->die_offset);
@@ -5652,6 +5710,34 @@ debug_dwarf (void)
print_indent = 0;
print_die (comp_unit_die (), stderr);
}
+
+/* Sanity checks on DIEs. */
+
+static void
+check_die (dw_die_ref die)
+{
+ /* A debugging information entry that is a member of an abstract
+ instance tree [that has DW_AT_inline] should not contain any
+ attributes which describe aspects of the subroutine which vary
+ between distinct inlined expansions or distinct out-of-line
+ expansions. */
+ unsigned ix;
+ dw_attr_ref a;
+ bool inline_found = false;
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ if (a->dw_attr == DW_AT_inline && a->dw_attr_val.v.val_unsigned)
+ inline_found = true;
+ if (inline_found)
+ {
+ /* Catch the most common mistakes. */
+ FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
+ gcc_assert (a->dw_attr != DW_AT_low_pc
+ && a->dw_attr != DW_AT_high_pc
+ && a->dw_attr != DW_AT_location
+ && a->dw_attr != DW_AT_frame_base
+ && a->dw_attr != DW_AT_GNU_all_call_sites);
+ }
+}
/* Start a new compilation unit DIE for an include file. OLD_UNIT is the CU
for the enclosing include file, if any. BINCL_DIE is the DW_TAG_GNU_BINCL
@@ -8799,9 +8885,10 @@ output_die (dw_die_ref die)
if (! die->comdat_type_p && die->die_id.die_symbol)
output_die_symbol (die);
- dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)",
+ dw2_asm_output_data_uleb128 (die->die_abbrev, "(DIE (%#lx) %s)%s",
(unsigned long)die->die_offset,
- dwarf_tag_name (die->die_tag));
+ dwarf_tag_name (die->die_tag),
+ die->dumped_early ? " (early)" : "");
FOR_EACH_VEC_SAFE_ELT (die->die_attr, ix, a)
{
@@ -16106,17 +16193,6 @@ add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p,
return tree_add_const_value_attribute_for_decl (die, decl);
}
-/* Add VARIABLE and DIE into deferred locations list. */
-
-static void
-defer_location (tree variable, dw_die_ref die)
-{
- deferred_locations entry;
- entry.variable = variable;
- entry.die = die;
- vec_safe_push (deferred_locations_list, entry);
-}
-
/* Helper function for tree_add_const_value_attribute. Natively encode
initializer INIT into an array. Return true if successful. */
@@ -16798,14 +16874,17 @@ add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr,
/* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing
possibly nested array subscripts in a flat sequence if COLLAPSE_P is true.
Note that the block of subscript information for an array type also
- includes information about the element type of the given array type. */
+ includes information about the element type of the given array type.
+
+ This function reuses previously set type and bound information if
+ available. */
static void
add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
{
unsigned dimension_number;
tree lower, upper;
- dw_die_ref subrange_die;
+ dw_die_ref child = type_die->die_child;
for (dimension_number = 0;
TREE_CODE (type) == ARRAY_TYPE && (dimension_number == 0 || collapse_p);
@@ -16819,7 +16898,37 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
/* Arrays come in three flavors: Unspecified bounds, fixed bounds,
and (in GNU C only) variable bounds. Handle all three forms
here. */
- subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+
+ /* Find and reuse a previously generated DW_TAG_subrange_type if
+ available.
+
+ For multi-dimensional arrays, as we iterate through the
+ various dimensions in the enclosing for loop above, we also
+ iterate through the DIE children and pick at each
+ DW_TAG_subrange_type previously generated (if available).
+ Each child DW_TAG_subrange_type DIE describes the range of
+ the current dimension. At this point we should have as many
+ DW_TAG_subrange_type's as we have dimensions in the
+ array. */
+ dw_die_ref subrange_die = NULL;
+ if (child)
+ while (1)
+ {
+ child = child->die_sib;
+ if (child->die_tag == DW_TAG_subrange_type)
+ subrange_die = child;
+ if (child == type_die->die_child)
+ {
+ /* If we wrapped around, stop looking next time. */
+ child = NULL;
+ break;
+ }
+ if (child->die_tag == DW_TAG_subrange_type)
+ break;
+ }
+ if (!subrange_die)
+ subrange_die = new_die (DW_TAG_subrange_type, type_die, NULL);
+
if (domain)
{
/* We have an array type with specified bounds. */
@@ -16827,7 +16936,8 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
upper = TYPE_MAX_VALUE (domain);
/* Define the index type. */
- if (TREE_TYPE (domain))
+ if (TREE_TYPE (domain)
+ && !get_AT (subrange_die, DW_AT_type))
{
/* ??? This is probably an Ada unnamed subrange type. Ignore the
TREE_TYPE field. We can't emit debug info for this
@@ -16849,8 +16959,9 @@ add_subscript_info (dw_die_ref type_die, tree type, bool collapse_p)
to produce useful results, go ahead and output the lower
bound solo, and hope the debugger can cope. */
- add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL);
- if (upper)
+ if (!get_AT (subrange_die, DW_AT_lower_bound))
+ add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL);
+ if (upper && !get_AT (subrange_die, DW_AT_upper_bound))
add_bound_info (subrange_die, DW_AT_upper_bound, upper, NULL);
}
@@ -17477,6 +17588,25 @@ decl_start_label (tree decl)
}
#endif
+/* For variable-length arrays that have been previously generated, but
+ may be incomplete due to missing subscript info, fill the subscript
+ info. Return TRUE if this is one of those cases. */
+static bool
+fill_variable_array_bounds (tree type)
+{
+ if (TREE_ASM_WRITTEN (type)
+ && TREE_CODE (type) == ARRAY_TYPE
+ && variably_modified_type_p (type, NULL))
+ {
+ dw_die_ref array_die = lookup_type_die (type);
+ if (!array_die)
+ return false;
+ add_subscript_info (array_die, type, !is_ada ());
+ return true;
+ }
+ return false;
+}
+
/* These routines generate the internal representation of the DIE's for
the compilation unit. Debugging information is collected by walking
the declaration trees passed in from dwarf2out_decl(). */
@@ -17484,7 +17614,6 @@ decl_start_label (tree decl)
static void
gen_array_type_die (tree type, dw_die_ref context_die)
{
- dw_die_ref scope_die = scope_die_for (type, context_die);
dw_die_ref array_die;
/* GNU compilers represent multidimensional array types as sequences of one
@@ -17498,6 +17627,11 @@ gen_array_type_die (tree type, dw_die_ref context_die)
flexibilty wrt arrays of variable size. */
bool collapse_nested_arrays = !is_ada ();
+
+ if (fill_variable_array_bounds (type))
+ return;
+
+ dw_die_ref scope_die = scope_die_for (type, context_die);
tree element_type;
/* Emit DW_TAG_string_type for Fortran character types (with kind 1 only, as
@@ -17853,8 +17987,64 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
{
tree node_or_origin = node ? node : origin;
tree ultimate_origin;
- dw_die_ref parm_die
- = new_die (DW_TAG_formal_parameter, context_die, node);
+ dw_die_ref parm_die = NULL;
+
+ if (TREE_CODE_CLASS (TREE_CODE (node_or_origin)) == tcc_declaration)
+ {
+ parm_die = lookup_decl_die (node);
+
+ /* If the contexts differ, we may not be talking about the same
+ thing. */
+ if (parm_die && parm_die->die_parent != context_die)
+ {
+ if (!DECL_ABSTRACT_P (node))
+ {
+ /* This can happen when creating an inlined instance, in
+ which case we need to create a new DIE that will get
+ annotated with DW_AT_abstract_origin. */
+ parm_die = NULL;
+ }
+ else
+ {
+ /* Reuse DIE even with a differing context.
+
+ This happens when called through
+ dwarf2out_abstract_function for formal parameter
+ packs. */
+ gcc_assert (parm_die->die_parent->die_tag
+ == DW_TAG_GNU_formal_parameter_pack);
+ }
+ }
+
+ if (parm_die && parm_die->die_parent == NULL)
+ {
+ /* Check that parm_die already has the right attributes that
+ we would have added below. If any attributes are
+ missing, fall through to add them. */
+ if (! DECL_ABSTRACT_P (node_or_origin)
+ && !get_AT (parm_die, DW_AT_location)
+ && !get_AT (parm_die, DW_AT_const_value))
+ /* We are missing location info, and are about to add it. */
+ ;
+ else
+ {
+ add_child_die (context_die, parm_die);
+ return parm_die;
+ }
+ }
+ }
+
+ /* If we have a previously generated DIE, use it, unless this is an
+ concrete instance (origin != NULL), in which case we need a new
+ DIE with a corresponding DW_AT_abstract_origin. */
+ bool reusing_die;
+ if (parm_die && origin == NULL)
+ reusing_die = true;
+ else
+ {
+ parm_die = new_die (DW_TAG_formal_parameter, context_die, node);
+ reusing_die = false;
+ }
switch (TREE_CODE_CLASS (TREE_CODE (node_or_origin)))
{
@@ -17862,6 +18052,10 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
ultimate_origin = decl_ultimate_origin (node_or_origin);
if (node || ultimate_origin)
origin = ultimate_origin;
+
+ if (reusing_die)
+ goto add_location;
+
if (origin != NULL)
add_abstract_origin_attribute (parm_die, origin);
else if (emit_name_p)
@@ -17881,6 +18075,7 @@ gen_formal_parameter_die (tree node, tree origin, bool emit_name_p,
decl_quals (node_or_origin),
context_die);
}
+ add_location:
if (origin == NULL && DECL_ARTIFICIAL (node))
add_AT_flag (parm_die, DW_AT_artificial, 1);
@@ -18394,26 +18589,94 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
{
tree origin = decl_ultimate_origin (decl);
dw_die_ref subr_die;
- tree outer_scope;
dw_die_ref old_die = lookup_decl_die (decl);
+
+ /* This function gets called multiple times for different stages of
+ the debug process. For example, for func() in this code:
+
+ namespace S
+ {
+ void func() { ... }
+ }
+
+ ...we get called 4 times. Twice in early debug and twice in
+ late debug:
+
+ Early debug
+ -----------
+
+ 1. Once while generating func() within the namespace. This is
+ the declaration. The declaration bit below is set, as the
+ context is the namespace.
+
+ A new DIE will be generated with DW_AT_declaration set.
+
+ 2. Once for func() itself. This is the specification. The
+ declaration bit below is clear as the context is the CU.
+
+ We will use the cached DIE from (1) to create a new DIE with
+ DW_AT_specification pointing to the declaration in (1).
+
+ Late debug via rest_of_handle_final()
+ -------------------------------------
+
+ 3. Once generating func() within the namespace. This is also the
+ declaration, as in (1), but this time we will early exit below
+ as we have a cached DIE and a declaration needs no additional
+ annotations (no locations), as the source declaration line
+ info is enough.
+
+ 4. Once for func() itself. As in (2), this is the specification,
+ but this time we will re-use the cached DIE, and just annotate
+ it with the location information that should now be available.
+
+ For something without namespaces, but with abstract instances, we
+ are also called a multiple times:
+
+ class Base
+ {
+ public:
+ Base (); // constructor declaration (1)
+ };
+
+ Base::Base () { } // constructor specification (2)
+
+ Early debug
+ -----------
+
+ 1. Once for the Base() constructor by virtue of it being a
+ member of the Base class. This is done via
+ rest_of_type_compilation.
+
+ This is a declaration, so a new DIE will be created with
+ DW_AT_declaration.
+
+ 2. Once for the Base() constructor definition, but this time
+ while generating the abstract instance of the base
+ constructor (__base_ctor) which is being generated via early
+ debug of reachable functions.
+
+ Even though we have a cached version of the declaration (1),
+ we will create a DW_AT_specification of the declaration DIE
+ in (1).
+
+ 3. Once for the __base_ctor itself, but this time, we generate
+ an DW_AT_abstract_origin version of the DW_AT_specification in
+ (2).
+
+ Late debug via rest_of_handle_final
+ -----------------------------------
+
+ 4. One final time for the __base_ctor (which will have a cached
+ DIE with DW_AT_abstract_origin created in (3). This time,
+ we will just annotate the location information now
+ available.
+ */
int declaration = (current_function_decl != decl
|| class_or_namespace_scope_p (context_die));
premark_used_types (DECL_STRUCT_FUNCTION (decl));
- /* It is possible to have both DECL_ABSTRACT_P and DECLARATION be true if we
- started to generate the abstract instance of an inline, decided to output
- its containing class, and proceeded to emit the declaration of the inline
- from the member list for the class. If so, DECLARATION takes priority;
- we'll get back to the abstract instance when done with the class. */
-
- /* The class-scope declaration DIE must be the primary DIE. */
- if (origin && declaration && class_or_namespace_scope_p (context_die))
- {
- origin = NULL;
- gcc_assert (!old_die);
- }
-
/* Now that the C++ front end lazily declares artificial member fns, we
might need to retrofit the declaration into its class. */
if (!declaration && !origin && !old_die
@@ -18422,6 +18685,8 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
&& debug_info_level > DINFO_LEVEL_TERSE)
old_die = force_decl_die (decl);
+ bool dumped_early = false;
+ /* An inlined instance, tag a new DIE with DW_AT_abstract_origin. */
if (origin != NULL)
{
gcc_assert (!declaration || local_scope_p (context_die));
@@ -18431,19 +18696,34 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
if (old_die && old_die->die_parent == NULL)
add_child_die (context_die, old_die);
- subr_die = new_die (DW_TAG_subprogram, context_die, decl);
- add_abstract_origin_attribute (subr_die, origin);
- /* This is where the actual code for a cloned function is.
- Let's emit linkage name attribute for it. This helps
- debuggers to e.g, set breakpoints into
- constructors/destructors when the user asks "break
- K::K". */
- add_linkage_name (subr_die, decl);
+ if (old_die && get_AT_ref (old_die, DW_AT_abstract_origin))
+ {
+ /* If we have a DW_AT_abstract_origin we have a working
+ cached version. */
+ subr_die = old_die;
+ }
+ else
+ {
+ subr_die = new_die (DW_TAG_subprogram, context_die, decl);
+ add_abstract_origin_attribute (subr_die, origin);
+ /* This is where the actual code for a cloned function is.
+ Let's emit linkage name attribute for it. This helps
+ debuggers to e.g, set breakpoints into
+ constructors/destructors when the user asks "break
+ K::K". */
+ add_linkage_name (subr_die, decl);
+ }
}
+ /* A cached copy, possibly from early dwarf generation. Reuse as
+ much as possible. */
else if (old_die)
{
- expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
- struct dwarf_file_data * file_index = lookup_filename (s.file);
+ /* A declaration that has been previously dumped needs no
+ additional information. */
+ if (declaration)
+ return;
+
+ dumped_early = old_die->dumped_early;
if (!get_AT_flag (old_die, DW_AT_declaration)
/* We can have a normal definition following an inline one in the
@@ -18453,7 +18733,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
{
/* Detect and ignore this case, where we are trying to output
something we have already output. */
- return;
+ if (get_AT (old_die, DW_AT_low_pc)
+ || get_AT (old_die, DW_AT_ranges))
+ return;
+
+ /* If we have no location information, this must be a
+ partially generated DIE from early dwarf generation.
+ Fall through and generate it. */
}
/* If the definition comes from the same place as the declaration,
@@ -18463,23 +18749,43 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
instances of inlines, since the spec requires the out-of-line copy
to have the same parent. For local class methods, this doesn't
apply; we just use the old DIE. */
- if ((is_cu_die (old_die->die_parent) || context_die == NULL)
- && (DECL_ARTIFICIAL (decl)
- || (get_AT_file (old_die, DW_AT_decl_file) == file_index
- && (get_AT_unsigned (old_die, DW_AT_decl_line)
- == (unsigned) s.line))))
+ expanded_location s = expand_location (DECL_SOURCE_LOCATION (decl));
+ struct dwarf_file_data * file_index = lookup_filename (s.file);
+ if ((is_cu_die (old_die->die_parent)
+ /* This condition fixes the inconsistency/ICE with the
+ following Fortran test (or some derivative thereof) while
+ building libgfortran:
+
+ module some_m
+ contains
+ logical function funky (FLAG)
+ funky = .true.
+ end function
+ end module
+ */
+ || old_die->die_parent->die_tag == DW_TAG_module
+ || context_die == NULL)
+ && (DECL_ARTIFICIAL (decl)
+ || (get_AT_file (old_die, DW_AT_decl_file) == file_index
+ && (get_AT_unsigned (old_die, DW_AT_decl_line)
+ == (unsigned) s.line))))
{
subr_die = old_die;
- /* Clear out the declaration attribute and the formal parameters.
- Do not remove all children, because it is possible that this
- declaration die was forced using force_decl_die(). In such
- cases die that forced declaration die (e.g. TAG_imported_module)
- is one of the children that we do not want to remove. */
- remove_AT (subr_die, DW_AT_declaration);
- remove_AT (subr_die, DW_AT_object_pointer);
- remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+ /* Clear out the declaration attribute, but leave the
+ parameters so they can be augmented with location
+ information later. Unless this was a declaration, in
+ which case, wipe out the nameless parameters and recreate
+ them further down. */
+ if (remove_AT (subr_die, DW_AT_declaration))
+ {
+
+ remove_AT (subr_die, DW_AT_object_pointer);
+ remove_child_TAG (subr_die, DW_TAG_formal_parameter);
+ }
}
+ /* Make a specification pointing to the previously built
+ declaration. */
else
{
subr_die = new_die (DW_TAG_subprogram, context_die, decl);
@@ -18501,6 +18807,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
}
}
}
+ /* Create a fresh DIE for anything else. */
else
{
subr_die = new_die (DW_TAG_subprogram, context_die, decl);
@@ -18527,6 +18834,11 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
add_accessibility_attribute (subr_die, decl);
}
+ /* Unless we have an existing non-declaration DIE, equate the new
+ DIE. */
+ if (!old_die || is_declaration_die (old_die))
+ equate_decl_number_to_die (decl, subr_die);
+
if (declaration)
{
if (!old_die || !get_AT (old_die, DW_AT_inline))
@@ -18544,17 +18856,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
if (lang_hooks.decls.function_decl_deleted_p (decl)
&& (! dwarf_strict))
add_AT_flag (subr_die, DW_AT_GNU_deleted, 1);
-
- /* The first time we see a member function, it is in the context of
- the class to which it belongs. We make sure of this by emitting
- the class first. The next time is the definition, which is
- handled above. The two may come from the same source text.
-
- Note that force_decl_die() forces function declaration die. It is
- later reused to represent definition. */
- equate_decl_number_to_die (decl, subr_die);
}
}
+ /* Tag abstract instances with DW_AT_inline. */
else if (DECL_ABSTRACT_P (decl))
{
if (DECL_DECLARED_INLINE_P (decl))
@@ -18575,18 +18879,15 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
if (DECL_DECLARED_INLINE_P (decl)
&& lookup_attribute ("artificial", DECL_ATTRIBUTES (decl)))
add_AT_flag (subr_die, DW_AT_artificial, 1);
-
- equate_decl_number_to_die (decl, subr_die);
}
- else if (!DECL_EXTERNAL (decl))
+ /* For non DECL_EXTERNALs, if range information is available, fill
+ the DIE with it. */
+ else if (!DECL_EXTERNAL (decl) && !early_dwarf)
{
HOST_WIDE_INT cfa_fb_offset;
- struct function *fun = DECL_STRUCT_FUNCTION (decl);
- if (!old_die || !get_AT (old_die, DW_AT_inline))
- equate_decl_number_to_die (decl, subr_die);
+ struct function *fun = DECL_STRUCT_FUNCTION (decl);
- gcc_checking_assert (fun);
if (!flag_reorder_blocks_and_partition)
{
dw_fde_ref fde = fun->fde;
@@ -18740,12 +19041,13 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
compute_frame_pointer_to_fb_displacement (cfa_fb_offset);
if (fun->static_chain_decl)
- add_AT_location_description (subr_die, DW_AT_static_link,
- loc_list_from_tree (fun->static_chain_decl, 2, NULL));
+ add_AT_location_description
+ (subr_die, DW_AT_static_link,
+ loc_list_from_tree (fun->static_chain_decl, 2, NULL));
}
/* Generate child dies for template paramaters. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
+ if (early_dwarf && debug_info_level > DINFO_LEVEL_TERSE)
gen_generic_params_dies (decl);
/* Now output descriptions of the arguments for this function. This gets
@@ -18764,12 +19066,17 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
if (debug_info_level <= DINFO_LEVEL_TERSE)
;
else if (declaration)
- gen_formal_types_die (decl, subr_die);
+ {
+ /* Only generate a prototype's parameters once. */
+ if (!dumped_early)
+ gen_formal_types_die (decl, subr_die);
+ }
else
{
/* Generate DIEs to represent all known formal parameters. */
tree parm = DECL_ARGUMENTS (decl);
- tree generic_decl = lang_hooks.decls.get_generic_function_decl (decl);
+ tree generic_decl = early_dwarf
+ ? lang_hooks.decls.get_generic_function_decl (decl) : NULL;
tree generic_decl_parm = generic_decl
? DECL_ARGUMENTS (generic_decl)
: NULL;
@@ -18834,11 +19141,14 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
gen_unspecified_parameters_die (decl, subr_die);
}
+ if (subr_die != old_die)
+ /* Add the calling convention attribute if requested. */
+ add_calling_convention_attribute (subr_die, decl);
+
/* Output Dwarf info for all of the stuff within the body of the function
- (if it has one - it may be just a declaration). */
- outer_scope = DECL_INITIAL (decl);
+ (if it has one - it may be just a declaration).
- /* OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
+ OUTER_SCOPE is a pointer to the outermost BLOCK node created to represent
a function. This BLOCK actually represents the outermost binding contour
for the function, i.e. the contour in which the function's formal
parameters and labels get declared. Curiously, it appears that the front
@@ -18852,6 +19162,7 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
a BLOCK node representing the function's outermost pair of curly braces,
and any blocks used for the base and member initializers of a C++
constructor function. */
+ tree outer_scope = DECL_INITIAL (decl);
if (! declaration && outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
{
int call_site_note_count = 0;
@@ -18861,6 +19172,9 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
if (DECL_NAME (DECL_RESULT (decl)))
gen_decl_die (DECL_RESULT (decl), NULL, subr_die);
+ /* The first time through decls_for_scope we will generate the
+ DIEs for the locals. The second time, we fill in the
+ location info. */
decls_for_scope (outer_scope, subr_die);
if (call_arg_locations && !dwarf_strict)
@@ -19012,10 +19326,6 @@ gen_subprogram_die (tree decl, dw_die_ref context_die)
call_site_count = -1;
tail_call_site_count = -1;
}
-
- if (subr_die != old_die)
- /* Add the calling convention attribute if requested. */
- add_calling_convention_attribute (subr_die, decl);
}
/* Returns a hash value for X (which really is a die_struct). */
@@ -19035,6 +19345,33 @@ block_die_hasher::equal (die_struct *x, die_struct *y)
return x->decl_id == y->decl_id && x->die_parent == y->die_parent;
}
+/* Return TRUE if DECL, which may have been previously generated as
+ OLD_DIE, is a candidate for a DW_AT_specification. DECLARATION is
+ true if decl (or its origin) is either an extern declaration or a
+ class/namespace scoped declaration.
+
+ The declare_in_namespace support causes us to get two DIEs for one
+ variable, both of which are declarations. We want to avoid
+ considering one to be a specification, so we must test for
+ DECLARATION and DW_AT_declaration. */
+static inline bool
+decl_will_get_specification_p (dw_die_ref old_die, tree decl, bool declaration)
+{
+ return (old_die && TREE_STATIC (decl) && !declaration
+ && get_AT_flag (old_die, DW_AT_declaration) == 1);
+}
+
+/* Return true if DECL is a local static. */
+
+static inline bool
+local_function_static (tree decl)
+{
+ gcc_assert (TREE_CODE (decl) == VAR_DECL);
+ return TREE_STATIC (decl)
+ && DECL_CONTEXT (decl)
+ && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL;
+}
+
/* Generate a DIE to represent a declared data object.
Either DECL or ORIGIN must be non-null. */
@@ -19047,7 +19384,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
tree ultimate_origin;
dw_die_ref var_die;
dw_die_ref old_die = decl ? lookup_decl_die (decl) : NULL;
- dw_die_ref origin_die;
bool declaration = (DECL_EXTERNAL (decl_or_origin)
|| class_or_namespace_scope_p (context_die));
bool specialization_p = false;
@@ -19162,11 +19498,74 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
return;
}
+ dw_die_ref origin_die = NULL;
+
+ if (old_die && old_die->dumped_early)
+ {
+ if (decl_will_get_specification_p (old_die, decl, declaration))
+ {
+ /* If we already have a DW_AT_specification, all we need is
+ location info. */
+ if (get_AT (old_die, DW_AT_specification))
+ {
+ var_die = old_die;
+ goto gen_variable_die_location;
+ }
+ /* Otherwise fall-thru so we can make a new variable die
+ along with a DW_AT_specification. */
+ }
+ else if (declaration)
+ {
+ /* A declaration that has been previously dumped, needs no
+ further annotations, since it doesn't need location on
+ the second pass. */
+ return;
+ }
+ else if (old_die->die_parent != context_die)
+ {
+ /* If the contexts differ, it means we _MAY_ not be talking
+ about the same thing. */
+ if (origin)
+ {
+ /* If we will be creating an inlined instance, we need a
+ new DIE that will get annotated with
+ DW_AT_abstract_origin. Clear things so we can get a
+ new DIE. */
+ gcc_assert (!DECL_ABSTRACT_P (decl));
+ old_die = NULL;
+ }
+ else
+ {
+ /* In some cases we end up with different contexts because
+ the context_die is set to the context of the containing
+ function, whereas the cached die is correctly set to the
+ (possible) enclosing lexical scope (DW_TAG_lexical_block).
+ In which case, special case it (hack).
+
+ See dwarf2out_decl and its use of
+ local_function_static to see how this can happened.
+ In java, it can happen with non local statics, hence
+ we do not check for TREE_STATIC here. */
+ gcc_assert (!DECL_CONTEXT (decl)
+ || TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL);
+ var_die = old_die;
+ goto gen_variable_die_location;
+ }
+ }
+ else
+ {
+ /* If a DIE was dumped early, it still needs location info.
+ Skip to where we fill the location bits. */
+ var_die = old_die;
+ goto gen_variable_die_location;
+ }
+ }
+
/* If the compiler emitted a definition for the DECL declaration
- and if we already emitted a DIE for it, don't emit a second
+ and we already emitted a DIE for it, don't emit a second
DIE for it again. Allow re-declarations of DECLs that are
inside functions, though. */
- if (old_die && declaration && !local_scope_p (context_die))
+ else if (old_die && !declaration && !local_scope_p (context_die))
return;
/* For static data members, the declaration in the class is supposed
@@ -19177,7 +19576,6 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
else
var_die = new_die (DW_TAG_variable, context_die, decl);
- origin_die = NULL;
if (origin != NULL)
origin_die = add_abstract_origin_attribute (var_die, origin);
@@ -19188,14 +19586,8 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
copy decls and set the DECL_ABSTRACT_P flag on them instead of
sharing them.
- ??? Duplicated blocks have been rewritten to use .debug_ranges.
-
- ??? The declare_in_namespace support causes us to get two DIEs for one
- variable, both of which are declarations. We want to avoid considering
- one to be a specification, so we must test that this DIE is not a
- declaration. */
- else if (old_die && TREE_STATIC (decl) && ! declaration
- && get_AT_flag (old_die, DW_AT_declaration) == 1)
+ ??? Duplicated blocks have been rewritten to use .debug_ranges. */
+ else if (decl_will_get_specification_p (old_die, decl, declaration))
{
/* This is a definition of a C++ class level static. */
add_AT_specification (var_die, old_die);
@@ -19249,9 +19641,11 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
if (declaration)
add_AT_flag (var_die, DW_AT_declaration, 1);
- if (decl && (DECL_ABSTRACT_P (decl) || declaration || old_die == NULL))
+ if (decl && (DECL_ABSTRACT_P (decl)
+ || !old_die || is_declaration_die (old_die)))
equate_decl_number_to_die (decl, var_die);
+ gen_variable_die_location:
if (! declaration
&& (! DECL_ABSTRACT_P (decl_or_origin)
/* Local static vars are shared between all clones/inlines,
@@ -19264,13 +19658,11 @@ gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
to add it again. */
&& (origin_die == NULL || get_AT (origin_die, DW_AT_location) == NULL))
{
- if (TREE_CODE (decl_or_origin) == VAR_DECL && TREE_STATIC (decl_or_origin)
- && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl_or_origin)))
- defer_location (decl_or_origin, var_die);
+ if (early_dwarf)
+ add_pubname (decl_or_origin, var_die);
else
- add_location_or_const_value_attribute (var_die, decl_or_origin,
+ add_location_or_const_value_attribute (var_die, decl_or_origin,
decl == NULL, DW_AT_location);
- add_pubname (decl_or_origin, var_die);
}
else
tree_add_const_value_attribute_for_decl (var_die, decl_or_origin);
@@ -19284,7 +19676,12 @@ gen_const_die (tree decl, dw_die_ref context_die)
dw_die_ref const_die;
tree type = TREE_TYPE (decl);
+ const_die = lookup_decl_die (decl);
+ if (const_die)
+ return;
+
const_die = new_die (DW_TAG_constant, context_die, decl);
+ equate_decl_number_to_die (decl, const_die);
add_name_and_src_coords_attributes (const_die, decl);
add_type_attribute (const_die, type, TYPE_QUAL_CONST, context_die);
if (TREE_PUBLIC (decl))
@@ -19300,14 +19697,20 @@ static void
gen_label_die (tree decl, dw_die_ref context_die)
{
tree origin = decl_ultimate_origin (decl);
- dw_die_ref lbl_die = new_die (DW_TAG_label, context_die, decl);
+ dw_die_ref lbl_die = lookup_decl_die (decl);
rtx insn;
char label[MAX_ARTIFICIAL_LABEL_BYTES];
- if (origin != NULL)
- add_abstract_origin_attribute (lbl_die, origin);
- else
- add_name_and_src_coords_attributes (lbl_die, decl);
+ if (!lbl_die)
+ {
+ lbl_die = new_die (DW_TAG_label, context_die, decl);
+ equate_decl_number_to_die (decl, lbl_die);
+
+ if (origin != NULL)
+ add_abstract_origin_attribute (lbl_die, origin);
+ else
+ add_name_and_src_coords_attributes (lbl_die, decl);
+ }
if (DECL_ABSTRACT_P (decl))
equate_decl_number_to_die (decl, lbl_die);
@@ -19461,13 +19864,56 @@ add_high_low_attributes (tree stmt, dw_die_ref die)
static void
gen_lexical_block_die (tree stmt, dw_die_ref context_die)
{
- dw_die_ref stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+ dw_die_ref old_die = BLOCK_DIE (stmt);
+ dw_die_ref stmt_die;
+ if (!old_die)
+ {
+ stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+ BLOCK_DIE (stmt) = stmt_die;
+ }
- if (call_arg_locations)
- BLOCK_DIE (stmt) = stmt_die;
+ if (BLOCK_ABSTRACT (stmt))
+ {
+ if (old_die)
+ {
+#ifdef ENABLE_CHECKING
+ /* This must have been generated early and it won't even
+ need location information since it's a DW_AT_inline
+ function. */
+ for (dw_die_ref c = context_die; c; c = c->die_parent)
+ if (c->die_tag == DW_TAG_inlined_subroutine
+ || c->die_tag == DW_TAG_subprogram)
+ {
+ gcc_assert (get_AT (c, DW_AT_inline));
+ break;
+ }
+#endif
+ return;
+ }
+ }
+ else if (BLOCK_ABSTRACT_ORIGIN (stmt))
+ {
+ /* If this is an inlined instance, create a new lexical die for
+ anything below to attach DW_AT_abstract_origin to. */
+ if (old_die)
+ {
+ stmt_die = new_die (DW_TAG_lexical_block, context_die, stmt);
+ BLOCK_DIE (stmt) = stmt_die;
+ old_die = NULL;
+ }
+ }
- if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
- add_high_low_attributes (stmt, stmt_die);
+ if (old_die)
+ stmt_die = old_die;
+
+ if (!early_dwarf)
+ {
+ /* A non abstract block whose blocks have already been reordered
+ should have the instruction range for this block. If so, set the
+ high/low attributes. */
+ if (! BLOCK_ABSTRACT (stmt) && TREE_ASM_WRITTEN (stmt))
+ add_high_low_attributes (stmt, stmt_die);
+ }
decls_for_scope (stmt, stmt_die);
}
@@ -19962,6 +20408,18 @@ static void
gen_struct_or_union_type_die (tree type, dw_die_ref context_die,
enum debug_info_usage usage)
{
+ /* Fill in the bound of variable-length fields in late dwarf if
+ still incomplete. */
+ if (TREE_ASM_WRITTEN (type)
+ && variably_modified_type_p (type, NULL)
+ && !early_dwarf)
+ {
+ tree member;
+ for (member = TYPE_FIELDS (type); member; member = DECL_CHAIN (member))
+ fill_variable_array_bounds (TREE_TYPE (member));
+ return;
+ }
+
dw_die_ref type_die = lookup_type_die (type);
dw_die_ref scope_die = 0;
int nested = 0;
@@ -20081,7 +20539,11 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
tree origin;
if (TREE_ASM_WRITTEN (decl))
- return;
+ {
+ if (DECL_ORIGINAL_TYPE (decl))
+ fill_variable_array_bounds (DECL_ORIGINAL_TYPE (decl));
+ return;
+ }
TREE_ASM_WRITTEN (decl) = 1;
type_die = new_die (DW_TAG_typedef, context_die, decl);
@@ -20097,6 +20559,9 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
{
type = DECL_ORIGINAL_TYPE (decl);
+ if (type == error_mark_node)
+ return;
+
gcc_assert (type != TREE_TYPE (decl));
equate_type_number_to_die (TREE_TYPE (decl), type_die);
}
@@ -20104,6 +20569,9 @@ gen_typedef_die (tree decl, dw_die_ref context_die)
{
type = TREE_TYPE (decl);
+ if (type == error_mark_node)
+ return;
+
if (is_naming_typedef_decl (TYPE_NAME (type)))
{
/* Here, we are in the case of decl being a typedef naming
@@ -20164,13 +20632,15 @@ gen_tagged_type_die (tree type,
|| !is_tagged_type (type))
return;
+ if (TREE_ASM_WRITTEN (type))
+ need_pop = 0;
/* If this is a nested type whose containing class hasn't been written
out yet, writing it out will cover this one, too. This does not apply
to instantiations of member class templates; they need to be added to
the containing class as they are generated. FIXME: This hurts the
idea of combining type decls from multiple TUs, since we can't predict
what set of template instantiations we'll get. */
- if (TYPE_CONTEXT (type)
+ else if (TYPE_CONTEXT (type)
&& AGGREGATE_TYPE_P (TYPE_CONTEXT (type))
&& ! TREE_ASM_WRITTEN (TYPE_CONTEXT (type)))
{
@@ -20302,7 +20772,18 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
}
if (TREE_ASM_WRITTEN (type))
- return;
+ {
+ /* Variable-length types may be incomplete even if
+ TREE_ASM_WRITTEN. For such types, fall through to
+ gen_array_type_die() and possibly fill in
+ DW_AT_{upper,lower}_bound attributes. */
+ if ((TREE_CODE (type) != ARRAY_TYPE
+ && TREE_CODE (type) != RECORD_TYPE
+ && TREE_CODE (type) != UNION_TYPE
+ && TREE_CODE (type) != QUAL_UNION_TYPE)
+ || !variably_modified_type_p (type, NULL))
+ return;
+ }
switch (TREE_CODE (type))
{
@@ -20354,9 +20835,6 @@ gen_type_die_with_usage (tree type, dw_die_ref context_die,
break;
case ARRAY_TYPE:
- gen_array_type_die (type, context_die);
- break;
-
case VECTOR_TYPE:
gen_array_type_die (type, context_die);
break;
@@ -20527,8 +21005,11 @@ process_scope_var (tree stmt, tree decl, tree origin, dw_die_ref context_die)
if (die != NULL && die->die_parent == NULL)
add_child_die (context_die, die);
else if (TREE_CODE (decl_or_origin) == IMPORTED_DECL)
- dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
- stmt, context_die);
+ {
+ if (early_dwarf)
+ dwarf2out_imported_module_or_decl_1 (decl_or_origin, DECL_NAME (decl_or_origin),
+ stmt, context_die);
+ }
else
gen_decl_die (decl, origin, context_die);
}
@@ -20742,7 +21223,9 @@ setup_namespace_context (tree thing, dw_die_ref context_die)
type) within its namespace, if appropriate.
For compatibility with older debuggers, namespace DIEs only contain
- declarations; all definitions are emitted at CU scope. */
+ declarations; all definitions are emitted at CU scope, with
+ DW_AT_specification pointing to the declaration (like with class
+ members). */
static dw_die_ref
declare_in_namespace (tree thing, dw_die_ref context_die)
@@ -21059,16 +21542,65 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
return NULL;
}
-/* Output debug information for global decl DECL. Called from toplev.c after
- compilation proper has finished. */
+/* Output initial debug information for global DECL. Called at the
+ end of the parsing process.
+
+ This is the initial debug generation process. As such, the DIEs
+ generated may be incomplete. A later debug generation pass
+ (dwarf2out_late_global_decl) will augment the information generated
+ in this pass (e.g., with complete location info). */
static void
-dwarf2out_global_decl (tree decl)
+dwarf2out_early_global_decl (tree decl)
{
- /* Output DWARF2 information for file-scope tentative data object
- declarations, file-scope (extern) function declarations (which
- had no corresponding body) and file-scope tagged type declarations
- and definitions which have not yet been forced out. */
+ set_early_dwarf s;
+
+ /* gen_decl_die() will set DECL_ABSTRACT because
+ cgraph_function_possibly_inlined_p() returns true. This is in
+ turn will cause DW_AT_inline attributes to be set.
+
+ This happens because at early dwarf generation, there is no
+ cgraph information, causing cgraph_function_possibly_inlined_p()
+ to return true. Trick cgraph_function_possibly_inlined_p()
+ while we generate dwarf early. */
+ bool save = symtab->global_info_ready;
+ symtab->global_info_ready = true;
+
+ /* We don't handle TYPE_DECLs. If required, they'll be reached via
+ other DECLs and they can point to template types or other things
+ that dwarf2out can't handle when done via dwarf2out_decl. */
+ if (TREE_CODE (decl) != TYPE_DECL
+ && TREE_CODE (decl) != PARM_DECL)
+ {
+ tree save_fndecl = current_function_decl;
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ {
+ /* No cfun means the symbol has no body, so there's nothing
+ to emit. */
+ if (!DECL_STRUCT_FUNCTION (decl))
+ goto early_decl_exit;
+
+ current_function_decl = decl;
+ }
+ dwarf2out_decl (decl);
+ if (TREE_CODE (decl) == FUNCTION_DECL)
+ current_function_decl = save_fndecl;
+ }
+ early_decl_exit:
+ symtab->global_info_ready = save;
+}
+
+/* Output debug information for global decl DECL. Called from
+ toplev.c after compilation proper has finished. */
+
+static void
+dwarf2out_late_global_decl (tree decl)
+{
+ /* Output any global decls we missed or fill-in any location
+ information we were unable to determine on the first pass.
+
+ Skip over functions because they were handled by the
+ debug_hooks->function_decl() call in rest_of_handle_final. */
if ((TREE_CODE (decl) != FUNCTION_DECL || !DECL_INITIAL (decl))
&& !POINTER_BOUNDS_P (decl))
dwarf2out_decl (decl);
@@ -21080,7 +21612,10 @@ static void
dwarf2out_type_decl (tree decl, int local)
{
if (!local)
- dwarf2out_decl (decl);
+ {
+ set_early_dwarf s;
+ dwarf2out_decl (decl);
+ }
}
/* Output debug information for imported module or decl DECL.
@@ -21188,6 +21723,8 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
gcc_assert (decl);
+ set_early_dwarf s;
+
/* To emit DW_TAG_imported_module or DW_TAG_imported_decl, we need two DIEs.
We need decl DIE for reference and scope die. First, get DIE for the decl
itself. */
@@ -21214,7 +21751,6 @@ dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
/* OK, now we have DIEs for decl as well as scope. Emit imported die. */
dwarf2out_imported_module_or_decl_1 (decl, name, context, scope_die);
-
}
/* Output debug information for namelists. */
@@ -21254,13 +21790,22 @@ gen_namelist_decl (tree name, dw_die_ref scope_die, tree item_decls)
}
-/* Write the debugging output for DECL. */
+/* Write the debugging output for DECL and return the DIE. */
static void
dwarf2out_decl (tree decl)
{
dw_die_ref context_die = comp_unit_die ();
+#ifdef ENABLE_CHECKING
+ /* Save some info so we can later determine if we erroneously
+ created a DIE for something we had already created a DIE for.
+ We should always be reusing DIEs created early. */
+ dw_die_ref early_die = NULL;
+ if (decl_die_table)
+ early_die = lookup_decl_die (decl);
+#endif
+
switch (TREE_CODE (decl))
{
case ERROR_MARK:
@@ -21313,21 +21858,8 @@ dwarf2out_decl (tree decl)
break;
case VAR_DECL:
- /* Ignore this VAR_DECL if it refers to a file-scope extern data object
- declaration and if the declaration was never even referenced from
- within this entire compilation unit. We suppress these DIEs in
- order to save space in the .debug section (by eliminating entries
- which are probably useless). Note that we must not suppress
- block-local extern declarations (whether used or not) because that
- would screw-up the debugger's name lookup mechanism and cause it to
- miss things which really ought to be in scope at a given point. */
- if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
- return;
-
/* For local statics lookup proper context die. */
- if (TREE_STATIC (decl)
- && DECL_CONTEXT (decl)
- && TREE_CODE (DECL_CONTEXT (decl)) == FUNCTION_DECL)
+ if (local_function_static (decl))
context_die = lookup_decl_die (DECL_CONTEXT (decl));
/* If we are in terse mode, don't generate any DIEs to represent any
@@ -21382,6 +21914,19 @@ dwarf2out_decl (tree decl)
}
gen_decl_die (decl, NULL, context_die);
+
+ dw_die_ref die = lookup_decl_die (decl);
+ if (die)
+ check_die (die);
+#ifdef ENABLE_CHECKING
+ /* If we early created a DIE, make sure it didn't get re-created by
+ mistake. */
+ if (early_die && early_die->dumped_early)
+ gcc_assert (early_die == die
+ /* We can have a differing DIE if and only if, the
+ new one is a specification of the old one. */
+ || get_AT_ref (die, DW_AT_specification) == early_die);
+#endif
}
/* Write the debugging output for DECL. */
@@ -21468,23 +22013,16 @@ dwarf_file_hasher::hash (dwarf_file_data *p)
section) and references to those files numbers (in the .debug_srcinfo
and.debug_macinfo sections). If the filename given as an argument is not
found in our current list, add it to the list and assign it the next
- available unique index number. In order to speed up searches, we remember
- the index of the filename was looked up last. This handles the majority of
- all searches. */
+ available unique index number. */
static struct dwarf_file_data *
lookup_filename (const char *file_name)
{
struct dwarf_file_data * created;
- /* Check to see if the file name that was searched on the previous
- call matches this file name. If so, return the index. */
- if (file_table_last_lookup
- && (file_name == file_table_last_lookup->filename
- || filename_cmp (file_table_last_lookup->filename, file_name) == 0))
- return file_table_last_lookup;
+ if (!file_name)
+ return NULL;
- /* Didn't match the previous lookup, search the table. */
dwarf_file_data **slot
= file_table->find_slot_with_hash (file_name, htab_hash_string (file_name),
INSERT);
@@ -24523,11 +25061,20 @@ optimize_location_lists (dw_die_ref die)
static void
dwarf2out_finish (const char *filename)
{
- limbo_die_node *node, *next_node;
comdat_type_node *ctnode;
- unsigned int i;
dw_die_ref main_comp_unit_die;
+ /* If the limbo list has anything, it should be things that were
+ created after the compilation proper. Anything from the early
+ dwarf pass, should have parents and should never be in the limbo
+ list this late. */
+ for (limbo_die_node *node = limbo_die_list; node; node = node->next)
+ gcc_assert (node->die->die_tag == DW_TAG_compile_unit
+ || !node->die->dumped_early);
+
+ /* Flush out any latecomers to the limbo party. */
+ dwarf2out_early_finish ();
+
/* PCH might result in DW_AT_producer string being restored from the
header compilation, so always fill it with empty string initially
and overwrite only here. */
@@ -24557,65 +25104,6 @@ dwarf2out_finish (const char *filename)
add_comp_dir_attribute (comp_unit_die ());
}
- if (deferred_locations_list)
- for (i = 0; i < deferred_locations_list->length (); i++)
- {
- add_location_or_const_value_attribute (
- (*deferred_locations_list)[i].die,
- (*deferred_locations_list)[i].variable,
- false,
- DW_AT_location);
- }
-
- /* Traverse the limbo die list, and add parent/child links. The only
- dies without parents that should be here are concrete instances of
- inline functions, and the comp_unit_die. We can ignore the comp_unit_die.
- For concrete instances, we can get the parent die from the abstract
- instance. */
- for (node = limbo_die_list; node; node = next_node)
- {
- dw_die_ref die = node->die;
- next_node = node->next;
-
- if (die->die_parent == NULL)
- {
- dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
-
- if (origin && origin->die_parent)
- add_child_die (origin->die_parent, die);
- else if (is_cu_die (die))
- ;
- else if (seen_error ())
- /* It's OK to be confused by errors in the input. */
- add_child_die (comp_unit_die (), die);
- else
- {
- /* In certain situations, the lexical block containing a
- nested function can be optimized away, which results
- in the nested function die being orphaned. Likewise
- with the return type of that nested function. Force
- this to be a child of the containing function.
-
- It may happen that even the containing function got fully
- inlined and optimized out. In that case we are lost and
- assign the empty child. This should not be big issue as
- the function is likely unreachable too. */
- gcc_assert (node->created_for);
-
- if (DECL_P (node->created_for))
- origin = get_context_die (DECL_CONTEXT (node->created_for));
- else if (TYPE_P (node->created_for))
- origin = scope_die_for (node->created_for, comp_unit_die ());
- else
- origin = comp_unit_die ();
-
- add_child_die (origin, die);
- }
- }
- }
-
- limbo_die_list = NULL;
-
#if ENABLE_ASSERT_CHECKING
{
dw_die_ref die = comp_unit_die (), c;
@@ -24625,23 +25113,6 @@ dwarf2out_finish (const char *filename)
resolve_addr (comp_unit_die ());
move_marked_base_types ();
- for (node = deferred_asm_name; node; node = node->next)
- {
- tree decl = node->created_for;
- /* When generating LTO bytecode we can not generate new assembler
- names at this point and all important decls got theirs via
- free-lang-data. */
- if (((!flag_generate_lto && !flag_generate_offload)
- || DECL_ASSEMBLER_NAME_SET_P (decl))
- && DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl))
- {
- add_linkage_attr (node->die, decl);
- move_linkage_attr (node->die);
- }
- }
-
- deferred_asm_name = NULL;
-
/* Walk through the list of incomplete types again, trying once more to
emit full debugging info for them. */
retry_incomplete_types ();
@@ -24680,6 +25151,7 @@ dwarf2out_finish (const char *filename)
/* Traverse the DIE's and add add sibling attributes to those DIE's
that have children. */
add_sibling_attributes (comp_unit_die ());
+ limbo_die_node *node;
for (node = limbo_die_list; node; node = node->next)
add_sibling_attributes (node->die);
for (ctnode = comdat_type_list; ctnode != NULL; ctnode = ctnode->next)
@@ -24941,6 +25413,83 @@ dwarf2out_finish (const char *filename)
output_indirect_strings ();
}
+/* Perform any cleanups needed after the early debug generation pass
+ has run. */
+
+static void
+dwarf2out_early_finish (void)
+{
+ limbo_die_node *node, *next_node;
+
+ /* Add DW_AT_linkage_name for all deferred DIEs. */
+ for (node = deferred_asm_name; node; node = node->next)
+ {
+ tree decl = node->created_for;
+ if (DECL_ASSEMBLER_NAME (decl) != DECL_NAME (decl)
+ /* A missing DECL_ASSEMBLER_NAME can be a constant DIE that
+ ended up in in deferred_asm_name before we knew it was
+ constant and never written to disk. */
+ && DECL_ASSEMBLER_NAME (decl))
+ {
+ add_linkage_attr (node->die, decl);
+ move_linkage_attr (node->die);
+ }
+ }
+ deferred_asm_name = NULL;
+
+ /* Traverse the limbo die list, and add parent/child links. The only
+ dies without parents that should be here are concrete instances of
+ inline functions, and the comp_unit_die. We can ignore the comp_unit_die.
+ For concrete instances, we can get the parent die from the abstract
+ instance.
+
+ The point here is to flush out the limbo list so that it is empty
+ and we don't need to stream it for LTO. */
+ for (node = limbo_die_list; node; node = next_node)
+ {
+ dw_die_ref die = node->die;
+ next_node = node->next;
+
+ if (die->die_parent == NULL)
+ {
+ dw_die_ref origin = get_AT_ref (die, DW_AT_abstract_origin);
+
+ if (origin && origin->die_parent)
+ add_child_die (origin->die_parent, die);
+ else if (is_cu_die (die))
+ ;
+ else if (seen_error ())
+ /* It's OK to be confused by errors in the input. */
+ add_child_die (comp_unit_die (), die);
+ else
+ {
+ /* In certain situations, the lexical block containing a
+ nested function can be optimized away, which results
+ in the nested function die being orphaned. Likewise
+ with the return type of that nested function. Force
+ this to be a child of the containing function.
+
+ It may happen that even the containing function got fully
+ inlined and optimized out. In that case we are lost and
+ assign the empty child. This should not be big issue as
+ the function is likely unreachable too. */
+ gcc_assert (node->created_for);
+
+ if (DECL_P (node->created_for))
+ origin = get_context_die (DECL_CONTEXT (node->created_for));
+ else if (TYPE_P (node->created_for))
+ origin = scope_die_for (node->created_for, comp_unit_die ());
+ else
+ origin = comp_unit_die ();
+
+ add_child_die (origin, die);
+ }
+ }
+ }
+
+ limbo_die_list = NULL;
+}
+
/* Reset all state within dwarf2out.c so that we can rerun the compiler
within the same process. For use by toplev::finalize. */
@@ -24979,13 +25528,10 @@ dwarf2out_c_finalize (void)
cold_text_section = NULL;
current_unit_personality = NULL;
- deferred_locations_list = NULL;
-
next_die_offset = 0;
single_comp_unit_die = NULL;
comdat_type_list = NULL;
limbo_die_list = NULL;
- deferred_asm_name = NULL;
file_table = NULL;
decl_die_table = NULL;
common_block_die_table = NULL;
@@ -25018,7 +25564,6 @@ dwarf2out_c_finalize (void)
poc_label_num = 0;
last_emitted_file = NULL;
label_num = 0;
- file_table_last_lookup = NULL;
tmpl_value_parm_die_table = NULL;
generic_type_instances = NULL;
frame_pointer_fb_offset = 0;