dwarf2out.c (free_AT, free_die): New fns.
* dwarf2out.c (free_AT, free_die): New fns. (remove_children): Call them. (output_line_info): Disable removal of duplicate notes. Generate minimal debug info for types with TYPE_DECL_SUPPRESS_INFO set. * dwarf2out.c (gen_struct_or_union_type_die): TYPE_DECL_SUPPRESS_INFO means pretend the type isn't defined. Don't defer emitting types. (gen_type_die_for_member): New fn. (gen_decl_die): Call it. (splice_child_die): New fn. (gen_member_die): Call it rather than generate duplicate dies. Defer emitting information for the abstract instance of an inline until we either inline it or emit an out-of-line copy. * dwarf2out.c (decl_ultimate_origin): Ignore DECL_ABSTRACT_ORIGIN from output_inline_function if DECL_ABSTRACT is also set. (block_ultimate_origin): Likewise. (gen_abstract_function): New fn. (gen_decl_die, gen_inlined_subroutine_die): Call it. (gen_subprogram_die): An abstract instance is not a declaration just because it doesn't match current_function_decl. Don't abort because DECL_DEFER_OUTPUT isn't set. Do abort if a declaration has an abstract origin. * toplev.c (rest_of_compilation): Don't emit dwarf2 info for the abstract instance here. From-SVN: r30659
This commit is contained in:
parent
50e159f655
commit
10a11b7561
|
@ -1,3 +1,32 @@
|
|||
1999-11-24 Jason Merrill <jason@casey.cygnus.com>
|
||||
|
||||
* dwarf2out.c (free_AT, free_die): New fns.
|
||||
(remove_children): Call them.
|
||||
(output_line_info): Disable removal of duplicate notes.
|
||||
|
||||
Generate minimal debug info for types with TYPE_DECL_SUPPRESS_INFO set.
|
||||
* dwarf2out.c (gen_struct_or_union_type_die): TYPE_DECL_SUPPRESS_INFO
|
||||
means pretend the type isn't defined.
|
||||
Don't defer emitting types.
|
||||
(gen_type_die_for_member): New fn.
|
||||
(gen_decl_die): Call it.
|
||||
(splice_child_die): New fn.
|
||||
(gen_member_die): Call it rather than generate duplicate dies.
|
||||
|
||||
Defer emitting information for the abstract instance of an inline
|
||||
until we either inline it or emit an out-of-line copy.
|
||||
* dwarf2out.c (decl_ultimate_origin): Ignore DECL_ABSTRACT_ORIGIN
|
||||
from output_inline_function if DECL_ABSTRACT is also set.
|
||||
(block_ultimate_origin): Likewise.
|
||||
(gen_abstract_function): New fn.
|
||||
(gen_decl_die, gen_inlined_subroutine_die): Call it.
|
||||
(gen_subprogram_die): An abstract instance is not a declaration
|
||||
just because it doesn't match current_function_decl. Don't abort
|
||||
because DECL_DEFER_OUTPUT isn't set. Do abort if a declaration
|
||||
has an abstract origin.
|
||||
* toplev.c (rest_of_compilation): Don't emit dwarf2 info for the
|
||||
abstract instance here.
|
||||
|
||||
Wed Nov 24 18:39:18 1999 Andrew Haley <aph@cygnus.com>
|
||||
|
||||
* config/sh/sh.h (SECONDARY_OUTPUT_RELOAD_CLASS): Add the case
|
||||
|
|
236
gcc/dwarf2out.c
236
gcc/dwarf2out.c
|
@ -2543,6 +2543,8 @@ static void gen_decl_die PROTO((tree, dw_die_ref));
|
|||
static unsigned lookup_filename PROTO((const char *));
|
||||
static void add_incomplete_type PROTO((tree));
|
||||
static void retry_incomplete_types PROTO((void));
|
||||
static void gen_type_die_for_member PROTO((tree, tree, dw_die_ref));
|
||||
static void gen_abstract_function PROTO((tree));
|
||||
|
||||
/* Section names used to hold DWARF debugging information. */
|
||||
#ifndef DEBUG_INFO_SECTION
|
||||
|
@ -3542,6 +3544,12 @@ static tree
|
|||
decl_ultimate_origin (decl)
|
||||
register tree decl;
|
||||
{
|
||||
/* output_inline_function sets DECL_ABSTRACT_ORIGIN for all the
|
||||
nodes in the function to point to themselves; ignore that if
|
||||
we're trying to output the abstract instance of this function. */
|
||||
if (DECL_ABSTRACT (decl) && DECL_ABSTRACT_ORIGIN (decl) == decl)
|
||||
return NULL_TREE;
|
||||
|
||||
#ifdef ENABLE_CHECKING
|
||||
if (DECL_FROM_INLINE (DECL_ORIGIN (decl)))
|
||||
/* Since the DECL_ABSTRACT_ORIGIN for a DECL is supposed to be the
|
||||
|
@ -3564,6 +3572,12 @@ block_ultimate_origin (block)
|
|||
{
|
||||
register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
|
||||
|
||||
/* output_inline_function sets BLOCK_ABSTRACT_ORIGIN for all the
|
||||
nodes in the function to point to themselves; ignore that if
|
||||
we're trying to output the abstract instance of this function. */
|
||||
if (BLOCK_ABSTRACT (block) && immediate_origin == block)
|
||||
return NULL_TREE;
|
||||
|
||||
if (immediate_origin == NULL_TREE)
|
||||
return NULL_TREE;
|
||||
else
|
||||
|
@ -4035,9 +4049,31 @@ is_fortran ()
|
|||
return (lang == DW_LANG_Fortran77 || lang == DW_LANG_Fortran90);
|
||||
}
|
||||
|
||||
/* Remove the specified attribute if present. */
|
||||
/* Free up the memory used by A. */
|
||||
|
||||
static inline void
|
||||
free_AT (a)
|
||||
dw_attr_ref a;
|
||||
{
|
||||
switch (AT_class (a))
|
||||
{
|
||||
case dw_val_class_addr:
|
||||
case dw_val_class_str:
|
||||
case dw_val_class_lbl_id:
|
||||
case dw_val_class_lbl_offset:
|
||||
free (a->dw_attr_val.v.val_str);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
free (a);
|
||||
}
|
||||
|
||||
/* Remove the specified attribute if present. */
|
||||
|
||||
static void
|
||||
remove_AT (die, attr_kind)
|
||||
register dw_die_ref die;
|
||||
register enum dwarf_attribute attr_kind;
|
||||
|
@ -4056,28 +4092,23 @@ remove_AT (die, attr_kind)
|
|||
}
|
||||
|
||||
if (removed != 0)
|
||||
{
|
||||
switch (AT_class (removed))
|
||||
{
|
||||
case dw_val_class_addr:
|
||||
case dw_val_class_str:
|
||||
case dw_val_class_lbl_id:
|
||||
case dw_val_class_lbl_offset:
|
||||
free (removed->dw_attr_val.v.val_str);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
||||
free (removed);
|
||||
}
|
||||
free_AT (removed);
|
||||
}
|
||||
}
|
||||
|
||||
/* Free up the memory used by DIE. */
|
||||
|
||||
static inline void
|
||||
free_die (die)
|
||||
dw_die_ref die;
|
||||
{
|
||||
remove_children (die);
|
||||
free (die);
|
||||
}
|
||||
|
||||
/* Discard the children of this DIE. */
|
||||
|
||||
static inline void
|
||||
static void
|
||||
remove_children (die)
|
||||
register dw_die_ref die;
|
||||
{
|
||||
|
@ -4097,10 +4128,10 @@ remove_children (die)
|
|||
register dw_attr_ref tmp_a = a;
|
||||
|
||||
a = a->dw_attr_next;
|
||||
free (tmp_a);
|
||||
free_AT (tmp_a);
|
||||
}
|
||||
|
||||
free (tmp_die);
|
||||
free_die (tmp_die);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -4122,6 +4153,34 @@ add_child_die (die, child_die)
|
|||
}
|
||||
}
|
||||
|
||||
/* Move CHILD, which must be a child of PARENT, to the front of
|
||||
PARENT's list of children. */
|
||||
|
||||
static void
|
||||
splice_child_die (parent, child)
|
||||
dw_die_ref parent, 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)
|
||||
child = get_AT_ref (child, DW_AT_specification);
|
||||
|
||||
if (parent == NULL || child == NULL || child->die_parent != parent)
|
||||
abort ();
|
||||
|
||||
for (p = &(parent->die_child); *p; p = &((*p)->die_sib))
|
||||
if (*p == child)
|
||||
{
|
||||
*p = child->die_sib;
|
||||
break;
|
||||
}
|
||||
|
||||
child->die_sib = parent->die_child;
|
||||
parent->die_child = child;
|
||||
}
|
||||
|
||||
/* Return a pointer to a newly created DIE node. */
|
||||
|
||||
static inline dw_die_ref
|
||||
|
@ -4165,7 +4224,7 @@ lookup_type_die (type)
|
|||
|
||||
/* Equate a DIE to a given type specifier. */
|
||||
|
||||
static void
|
||||
static inline void
|
||||
equate_type_number_to_die (type, type_die)
|
||||
register tree type;
|
||||
register dw_die_ref type_die;
|
||||
|
@ -5666,12 +5725,18 @@ output_line_info ()
|
|||
{
|
||||
register dw_line_info_ref line_info = &line_info_table[lt_index];
|
||||
|
||||
#if 0
|
||||
/* Disable this optimization for now; GDB wants to see two line notes
|
||||
at the beginning of a function so it can find the end of the
|
||||
prologue. */
|
||||
|
||||
/* Don't emit anything for redundant notes. Just updating the
|
||||
address doesn't accomplish anything, because we already assume
|
||||
that anything after the last address is this line. */
|
||||
if (line_info->dw_line_num == current_line
|
||||
&& line_info->dw_file_num == current_file)
|
||||
continue;
|
||||
#endif
|
||||
|
||||
/* Emit debug info for the address of the current line, choosing
|
||||
the encoding that uses the least amount of space. */
|
||||
|
@ -5824,11 +5889,13 @@ output_line_info ()
|
|||
register dw_separate_line_info_ref line_info
|
||||
= &separate_line_info_table[lt_index];
|
||||
|
||||
#if 0
|
||||
/* Don't emit anything for redundant notes. */
|
||||
if (line_info->dw_line_num == current_line
|
||||
&& line_info->dw_file_num == current_file
|
||||
&& line_info->function == function)
|
||||
goto cont;
|
||||
#endif
|
||||
|
||||
/* Emit debug info for the address of the current line. If this is
|
||||
a new function, or the first line of a function, then we need
|
||||
|
@ -5944,7 +6011,9 @@ output_line_info ()
|
|||
fputc ('\n', asm_out_file);
|
||||
}
|
||||
|
||||
#if 0
|
||||
cont:
|
||||
#endif
|
||||
++lt_index;
|
||||
|
||||
/* If we're done with a function, end its sequence. */
|
||||
|
@ -8192,6 +8261,55 @@ gen_formal_types_die (function_or_method_type, context_die)
|
|||
}
|
||||
}
|
||||
|
||||
/* We want to generate the DIE for TYPE so that we can generate the
|
||||
die for MEMBER, which has been defined; we will need to refer back
|
||||
to the member declaration nested within TYPE. If we're trying to
|
||||
generate minimal debug info for TYPE, processing TYPE won't do the
|
||||
trick; we need to attach the member declaration by hand. */
|
||||
|
||||
static void
|
||||
gen_type_die_for_member (type, member, context_die)
|
||||
tree type, member;
|
||||
dw_die_ref context_die;
|
||||
{
|
||||
gen_type_die (type, context_die);
|
||||
|
||||
/* If we're trying to avoid duplicate debug info, we may not have
|
||||
emitted the member decl for this function. Emit it now. */
|
||||
if (TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type))
|
||||
&& ! lookup_decl_die (member))
|
||||
{
|
||||
if (decl_ultimate_origin (member))
|
||||
abort ();
|
||||
|
||||
push_decl_scope (type);
|
||||
if (TREE_CODE (member) == FUNCTION_DECL)
|
||||
gen_subprogram_die (member, lookup_type_die (type));
|
||||
else
|
||||
gen_variable_die (member, lookup_type_die (type));
|
||||
pop_decl_scope ();
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate the DWARF2 info for the "abstract" instance
|
||||
of a function which we may later generate inlined and/or
|
||||
out-of-line instances of. */
|
||||
|
||||
static void
|
||||
gen_abstract_function (decl)
|
||||
tree decl;
|
||||
{
|
||||
register dw_die_ref old_die = lookup_decl_die (decl);
|
||||
|
||||
if (old_die && get_AT_unsigned (old_die, DW_AT_inline))
|
||||
/* We've already generated the abstract instance. */
|
||||
return;
|
||||
|
||||
set_decl_abstract_flags (decl, 1);
|
||||
dwarf2out_decl (decl);
|
||||
set_decl_abstract_flags (decl, 0);
|
||||
}
|
||||
|
||||
/* Generate a DIE to represent a declared function (either file-scope or
|
||||
block-local). */
|
||||
|
||||
|
@ -8208,13 +8326,23 @@ gen_subprogram_die (decl, context_die)
|
|||
register tree outer_scope;
|
||||
register dw_die_ref old_die = lookup_decl_die (decl);
|
||||
register int declaration
|
||||
= (current_function_decl != decl
|
||||
= ((current_function_decl != decl && ! DECL_ABSTRACT (decl))
|
||||
|| (context_die
|
||||
&& (context_die->die_tag == DW_TAG_structure_type
|
||||
|| context_die->die_tag == DW_TAG_union_type)));
|
||||
|
||||
/* Note that it is possible to have both DECL_ABSTRACT 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. In that
|
||||
case, `declaration' takes priority; we'll get back to the abstract
|
||||
instance when we're done with the class. */
|
||||
|
||||
if (origin != NULL)
|
||||
{
|
||||
if (declaration)
|
||||
abort ();
|
||||
|
||||
subr_die = new_die (DW_TAG_subprogram, context_die);
|
||||
add_abstract_origin_attribute (subr_die, origin);
|
||||
}
|
||||
|
@ -8324,22 +8452,20 @@ gen_subprogram_die (decl, context_die)
|
|||
}
|
||||
else if (DECL_ABSTRACT (decl))
|
||||
{
|
||||
/* ??? Checking DECL_DEFER_OUTPUT is correct for static inline functions,
|
||||
but not for extern inline functions. We can't get this completely
|
||||
correct because information about whether the function was declared
|
||||
inline is not saved anywhere. */
|
||||
if (DECL_DEFER_OUTPUT (decl))
|
||||
if (DECL_INLINE (decl) && !flag_no_inline)
|
||||
{
|
||||
if (DECL_INLINE (decl) && !flag_no_inline)
|
||||
/* ??? Checking DECL_DEFER_OUTPUT is correct for static
|
||||
inline functions, but not for extern inline functions.
|
||||
We can't get this completely correct because information
|
||||
about whether the function was declared inline is not
|
||||
saved anywhere. */
|
||||
if (DECL_DEFER_OUTPUT (decl))
|
||||
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_inlined);
|
||||
else
|
||||
add_AT_unsigned (subr_die, DW_AT_inline,
|
||||
DW_INL_declared_not_inlined);
|
||||
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
|
||||
}
|
||||
else if (DECL_INLINE (decl) && !flag_no_inline)
|
||||
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_inlined);
|
||||
else
|
||||
abort ();
|
||||
add_AT_unsigned (subr_die, DW_AT_inline, DW_INL_declared_not_inlined);
|
||||
|
||||
equate_decl_number_to_die (decl, subr_die);
|
||||
}
|
||||
|
@ -8637,6 +8763,9 @@ gen_inlined_subroutine_die (stmt, context_die, depth)
|
|||
register tree decl = block_ultimate_origin (stmt);
|
||||
char label[MAX_ARTIFICIAL_LABEL_BYTES];
|
||||
|
||||
/* Emit info for the abstract instance first, if we haven't yet. */
|
||||
gen_abstract_function (decl);
|
||||
|
||||
add_abstract_origin_attribute (subr_die, decl);
|
||||
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
|
||||
next_block_number);
|
||||
|
@ -8833,6 +8962,7 @@ gen_member_die (type, context_die)
|
|||
register dw_die_ref context_die;
|
||||
{
|
||||
register tree member;
|
||||
dw_die_ref child;
|
||||
|
||||
/* If this is not an incomplete type, output descriptions of each of its
|
||||
members. Note that as we output the DIEs necessary to represent the
|
||||
|
@ -8860,14 +8990,33 @@ gen_member_die (type, context_die)
|
|||
|
||||
/* Now output info about the data members and type members. */
|
||||
for (member = TYPE_FIELDS (type); member; member = TREE_CHAIN (member))
|
||||
gen_decl_die (member, context_die);
|
||||
{
|
||||
/* If we thought we were generating minimal debug info for TYPE
|
||||
and then changed our minds, some of the member declarations
|
||||
may have already been defined. Don't define them again, but
|
||||
do put them in the right order. */
|
||||
|
||||
child = lookup_decl_die (member);
|
||||
if (child)
|
||||
splice_child_die (context_die, child);
|
||||
else
|
||||
gen_decl_die (member, context_die);
|
||||
}
|
||||
|
||||
/* Now output info about the function members (if any). */
|
||||
for (member = TYPE_METHODS (type); member; member = TREE_CHAIN (member))
|
||||
gen_decl_die (member, context_die);
|
||||
{
|
||||
child = lookup_decl_die (member);
|
||||
if (child)
|
||||
splice_child_die (context_die, child);
|
||||
else
|
||||
gen_decl_die (member, context_die);
|
||||
}
|
||||
}
|
||||
|
||||
/* Generate a DIE for a structure or union type. */
|
||||
/* Generate a DIE for a structure or union type. If TYPE_DECL_SUPPRESS_DEBUG
|
||||
is set, we pretend that the type was never defined, so we only get the
|
||||
member DIEs needed by later specification DIEs. */
|
||||
|
||||
static void
|
||||
gen_struct_or_union_type_die (type, context_die)
|
||||
|
@ -8877,8 +9026,10 @@ gen_struct_or_union_type_die (type, context_die)
|
|||
register dw_die_ref type_die = lookup_type_die (type);
|
||||
register dw_die_ref scope_die = 0;
|
||||
register int nested = 0;
|
||||
int complete = (TYPE_SIZE (type)
|
||||
&& ! TYPE_DECL_SUPPRESS_DEBUG (TYPE_STUB_DECL (type)));
|
||||
|
||||
if (type_die && ! TYPE_SIZE (type))
|
||||
if (type_die && ! complete)
|
||||
return;
|
||||
|
||||
if (TYPE_CONTEXT (type) != NULL_TREE
|
||||
|
@ -8912,7 +9063,7 @@ gen_struct_or_union_type_die (type, context_die)
|
|||
}
|
||||
/* If this type has been completed, then give it a byte_size attribute and
|
||||
then give a list of members. */
|
||||
else if (TYPE_SIZE (type))
|
||||
else if (complete)
|
||||
{
|
||||
/* Prevent infinite recursion in cases where the type of some member of
|
||||
this type is expressed in terms of this type itself. */
|
||||
|
@ -9386,6 +9537,11 @@ gen_decl_die (decl, context_die)
|
|||
&& (current_function_decl == NULL_TREE || ! DECL_ARTIFICIAL (decl)))
|
||||
break;
|
||||
|
||||
/* Emit info for the abstract instance first, if we haven't yet. */
|
||||
origin = decl_ultimate_origin (decl);
|
||||
if (origin)
|
||||
gen_abstract_function (origin);
|
||||
|
||||
if (debug_info_level > DINFO_LEVEL_TERSE)
|
||||
{
|
||||
/* Before we describe the FUNCTION_DECL itself, make sure that we
|
||||
|
@ -9395,7 +9551,7 @@ gen_decl_die (decl, context_die)
|
|||
/* And its containing type. */
|
||||
origin = decl_class_context (decl);
|
||||
if (origin != NULL_TREE)
|
||||
gen_type_die (origin, context_die);
|
||||
gen_type_die_for_member (origin, decl, context_die);
|
||||
|
||||
/* And its virtual context. */
|
||||
if (DECL_VINDEX (decl) != NULL_TREE)
|
||||
|
@ -9450,7 +9606,7 @@ gen_decl_die (decl, context_die)
|
|||
/* And its containing type. */
|
||||
origin = decl_class_context (decl);
|
||||
if (origin != NULL_TREE)
|
||||
gen_type_die (origin, context_die);
|
||||
gen_type_die_for_member (origin, decl, context_die);
|
||||
|
||||
/* Now output the DIE to represent the data object itself. This gets
|
||||
complicated because of the possibility that the VAR_DECL really
|
||||
|
|
11
gcc/toplev.c
11
gcc/toplev.c
|
@ -3689,17 +3689,6 @@ rest_of_compilation (decl)
|
|||
TIMEVAR (symout_time, dwarfout_file_scope_decl (decl, 0));
|
||||
set_decl_abstract_flags (decl, 0);
|
||||
}
|
||||
#endif
|
||||
#ifdef DWARF2_DEBUGGING_INFO
|
||||
/* Generate the DWARF2 info for the "abstract" instance
|
||||
of a function which we may later generate inlined and/or
|
||||
out-of-line instances of. */
|
||||
if (write_symbols == DWARF2_DEBUG)
|
||||
{
|
||||
set_decl_abstract_flags (decl, 1);
|
||||
TIMEVAR (symout_time, dwarf2out_decl (decl));
|
||||
set_decl_abstract_flags (decl, 0);
|
||||
}
|
||||
#endif
|
||||
TIMEVAR (integration_time, save_for_inline_nocopy (decl));
|
||||
DECL_SAVED_INSNS (decl)->inlinable = inlinable;
|
||||
|
|
Loading…
Reference in New Issue