/* Output Dwarf2 format symbol table information from GCC.
Copyright (C) 1992, 1993, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
- 2003, 2004, 2005, 2006, 2007, 2008 Free Software Foundation, Inc.
+ 2003, 2004, 2005, 2006, 2007, 2008, 2009 Free Software Foundation, Inc.
Contributed by Gary Funck (gary@intrepid.com).
Derived from DWARF 1 implementation of Ron Guilmette (rfg@monkeys.com).
Extensively modified by Jason Merrill (jason@cygnus.com).
#define DWARF2_FRAME_REG_OUT(REGNO, FOR_EH) (REGNO)
#endif
+/* Save the result of dwarf2out_do_frame across PCH. */
+static GTY(()) bool saved_do_cfi_asm = 0;
+
/* Decide whether we want to emit frame unwind information for the current
translation unit. */
we're not going to output frame or unwind info. */
return (write_symbols == DWARF2_DEBUG
|| write_symbols == VMS_AND_DWARF2_DEBUG
- || DWARF2_FRAME_INFO
+ || DWARF2_FRAME_INFO || saved_do_cfi_asm
#ifdef DWARF2_UNWIND_INFO
|| (DWARF2_UNWIND_INFO
&& (flag_unwind_tables
#endif
if (!flag_dwarf2_cfi_asm || !dwarf2out_do_frame ())
return false;
- if (!eh_personality_libfunc)
+ if (saved_do_cfi_asm || !eh_personality_libfunc)
return true;
if (!HAVE_GAS_CFI_PERSONALITY_DIRECTIVE)
return false;
if ((enc & 0x70) != 0 && (enc & 0x70) != DW_EH_PE_pcrel)
return false;
+ saved_do_cfi_asm = true;
return true;
}
#ifdef DWARF2_UNWIND_INFO
static void initial_return_save (rtx);
#endif
-static HOST_WIDE_INT stack_adjust_offset (const_rtx);
+static HOST_WIDE_INT stack_adjust_offset (const_rtx, HOST_WIDE_INT,
+ HOST_WIDE_INT);
static void output_cfi (dw_cfi_ref, dw_fde_ref, int);
static void output_cfi_directive (dw_cfi_ref);
static void output_call_frame_info (int);
contains. */
static HOST_WIDE_INT
-stack_adjust_offset (const_rtx pattern)
+stack_adjust_offset (const_rtx pattern, HOST_WIDE_INT cur_args_size,
+ HOST_WIDE_INT cur_offset)
{
const_rtx src = SET_SRC (pattern);
const_rtx dest = SET_DEST (pattern);
if (dest == stack_pointer_rtx)
{
- /* (set (reg sp) (plus (reg sp) (const_int))) */
code = GET_CODE (src);
+
+ /* Assume (set (reg sp) (reg whatever)) sets args_size
+ level to 0. */
+ if (code == REG && src != stack_pointer_rtx)
+ {
+ offset = -cur_args_size;
+#ifndef STACK_GROWS_DOWNWARD
+ offset = -offset;
+#endif
+ return offset - cur_offset;
+ }
+
if (! (code == PLUS || code == MINUS)
|| XEXP (src, 0) != stack_pointer_rtx
|| GET_CODE (XEXP (src, 1)) != CONST_INT)
return 0;
+ /* (set (reg sp) (plus (reg sp) (const_int))) */
offset = INTVAL (XEXP (src, 1));
if (code == PLUS)
offset = -offset;
+ return offset;
}
- else if (MEM_P (dest))
+
+ if (MEM_P (src) && !MEM_P (dest))
+ dest = src;
+ if (MEM_P (dest))
{
/* (set (mem (pre_dec (reg sp))) (foo)) */
src = XEXP (dest, 0);
|| sibcall_epilogue_contains (insn))
/* Nothing */;
else if (GET_CODE (PATTERN (insn)) == SET)
- offset = stack_adjust_offset (PATTERN (insn));
+ offset = stack_adjust_offset (PATTERN (insn), cur_args_size, 0);
else if (GET_CODE (PATTERN (insn)) == PARALLEL
|| GET_CODE (PATTERN (insn)) == SEQUENCE)
{
for them. */
for (i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
- offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i));
+ offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i),
+ cur_args_size, offset);
}
}
else
rtx elem = XVECEXP (expr, 0, i);
if (GET_CODE (elem) == SET && !RTX_FRAME_RELATED_P (elem))
- offset += stack_adjust_offset (elem);
+ offset += stack_adjust_offset (elem, cur_args_size, offset);
}
}
}
body = PATTERN (insn);
if (GET_CODE (body) == SEQUENCE)
{
+ HOST_WIDE_INT dest_args_size = cur_args_size;
for (i = 1; i < XVECLEN (body, 0); i++)
+ if (INSN_ANNULLED_BRANCH_P (XVECEXP (body, 0, 0))
+ && INSN_FROM_TARGET_P (XVECEXP (body, 0, i)))
+ dest_args_size
+ = compute_barrier_args_size_1 (XVECEXP (body, 0, i),
+ dest_args_size, &next);
+ else
+ cur_args_size
+ = compute_barrier_args_size_1 (XVECEXP (body, 0, i),
+ cur_args_size, &next);
+
+ if (INSN_ANNULLED_BRANCH_P (XVECEXP (body, 0, 0)))
+ compute_barrier_args_size_1 (XVECEXP (body, 0, 0),
+ dest_args_size, &next);
+ else
cur_args_size
- = compute_barrier_args_size_1 (XVECEXP (body, 0, i),
+ = compute_barrier_args_size_1 (XVECEXP (body, 0, 0),
cur_args_size, &next);
- cur_args_size
- = compute_barrier_args_size_1 (XVECEXP (body, 0, 0),
- cur_args_size, &next);
}
else
cur_args_size
if (prologue_epilogue_contains (insn) || sibcall_epilogue_contains (insn))
return;
+ /* If INSN is an instruction from target of an annulled branch, the
+ effects are for the target only and so current argument size
+ shouldn't change at all. */
+ if (final_sequence
+ && INSN_ANNULLED_BRANCH_P (XVECEXP (final_sequence, 0, 0))
+ && INSN_FROM_TARGET_P (insn))
+ return;
+
/* If only calls can throw, and we have a frame pointer,
save up adjustments until we see the CALL_INSN. */
if (!flag_asynchronous_unwind_tables && cfa.reg != STACK_POINTER_REGNUM)
#endif
}
else if (GET_CODE (PATTERN (insn)) == SET)
- offset = stack_adjust_offset (PATTERN (insn));
+ offset = stack_adjust_offset (PATTERN (insn), args_size, 0);
else if (GET_CODE (PATTERN (insn)) == PARALLEL
|| GET_CODE (PATTERN (insn)) == SEQUENCE)
{
for them. */
for (offset = 0, i = XVECLEN (PATTERN (insn), 0) - 1; i >= 0; i--)
if (GET_CODE (XVECEXP (PATTERN (insn), 0, i)) == SET)
- offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i));
+ offset += stack_adjust_offset (XVECEXP (PATTERN (insn), 0, i),
+ args_size, offset);
}
else
return;
{
/* Stack adjustment combining might combine some post-prologue
stack adjustment into a prologue stack adjustment. */
- HOST_WIDE_INT offset = stack_adjust_offset (elem);
+ HOST_WIDE_INT offset = stack_adjust_offset (elem, args_size, 0);
if (offset != 0)
dwarf2out_args_size_adjust (offset, label);
typedef struct dw_loc_descr_struct *dw_loc_descr_ref;
typedef struct dw_loc_list_struct *dw_loc_list_ref;
+typedef struct deferred_locations_struct GTY(())
+{
+ tree variable;
+ dw_die_ref die;
+} deferred_locations;
+
+DEF_VEC_O(deferred_locations);
+DEF_VEC_ALLOC_O(deferred_locations,gc);
+
+static GTY(()) VEC(deferred_locations, gc) *deferred_locations_list;
+
/* Each DIE may have a series of attribute/value pairs. Values
can take on several forms. The forms that are used in this
implementation are listed below. */
static void dwarf2out_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,
+ dw_die_ref);
static void dwarf2out_abstract_function (tree);
static void dwarf2out_var_location (rtx);
static void dwarf2out_begin_function (tree);
The key is a DECL_UID() which is a unique number identifying each decl. */
static GTY ((param_is (struct die_struct))) htab_t decl_die_table;
+/* A hash table of references to DIE's that describe COMMON blocks.
+ The key is DECL_UID() ^ die_parent. */
+static GTY ((param_is (struct die_struct))) htab_t common_block_die_table;
+
/* Node of the variable location list. */
struct var_loc_node GTY ((chain_next ("%h.next")))
{
static const char *dwarf_attr_name (unsigned);
static const char *dwarf_form_name (unsigned);
static tree decl_ultimate_origin (const_tree);
-static tree block_ultimate_origin (const_tree);
static tree decl_class_context (tree);
static void add_dwarf_attr (dw_die_ref, dw_attr_ref);
static inline enum dw_val_class AT_class (dw_attr_ref);
static hashval_t decl_die_table_hash (const void *);
static int decl_die_table_eq (const void *, const void *);
static dw_die_ref lookup_decl_die (tree);
+static hashval_t common_block_die_table_hash (const void *);
+static int common_block_die_table_eq (const void *, const void *);
static hashval_t decl_loc_table_hash (const void *);
static int decl_loc_table_eq (const void *, const void *);
static var_loc_list *lookup_decl_loc (const_tree);
static void add_sibling_attributes (dw_die_ref);
static void build_abbrev_table (dw_die_ref);
static void output_location_lists (dw_die_ref);
-static int constant_size (long unsigned);
+static int constant_size (unsigned HOST_WIDE_INT);
static unsigned long size_of_die (dw_die_ref);
static void calc_die_sizes (dw_die_ref);
static void mark_dies (dw_die_ref);
return DECL_ABSTRACT_ORIGIN (decl);
}
-/* Determine the "ultimate origin" of a block. The block may be an inlined
- instance of an inlined instance of a block which is local to an inline
- function, so we have to trace all of the way back through the origin chain
- to find out what sort of node actually served as the original seed for the
- given block. */
-
-static tree
-block_ultimate_origin (const_tree block)
-{
- 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
- {
- tree ret_val;
- tree lookahead = immediate_origin;
-
- do
- {
- ret_val = lookahead;
- lookahead = (TREE_CODE (ret_val) == BLOCK
- ? BLOCK_ABSTRACT_ORIGIN (ret_val) : NULL);
- }
- while (lookahead != NULL && lookahead != ret_val);
-
- /* The block's abstract origin chain may not be the *ultimate* origin of
- the block. It could lead to a DECL that has an abstract origin set.
- If so, we want that DECL's abstract origin (which is what DECL_ORIGIN
- will give us if it has one). Note that DECL's abstract origins are
- supposed to be the most distant ancestor (or so decl_ultimate_origin
- claims), so we don't need to loop following the DECL origins. */
- if (DECL_P (ret_val))
- return DECL_ORIGIN (ret_val);
-
- return ret_val;
- }
-}
-
/* Get the class to which DECL belongs, if any. In g++, the DECL_CONTEXT
of a virtual function may refer to a base class, so we check the 'this'
parameter. */
/* Return the power-of-two number of bytes necessary to represent VALUE. */
static int
-constant_size (long unsigned int value)
+constant_size (unsigned HOST_WIDE_INT value)
{
int log;
distinction between OP_REG and OP_BASEREG. */
if (REGNO (rtl) < FIRST_PSEUDO_REGISTER)
mem_loc_result = based_loc_descr (rtl, 0, VAR_INIT_STATUS_INITIALIZED);
+ else if (stack_realign_drap
+ && crtl->drap_reg
+ && crtl->args.internal_arg_pointer == rtl
+ && REGNO (crtl->drap_reg) < FIRST_PSEUDO_REGISTER)
+ {
+ /* If RTL is internal_arg_pointer, which has been optimized
+ out, use DRAP instead. */
+ mem_loc_result = based_loc_descr (crtl->drap_reg, 0,
+ VAR_INIT_STATUS_INITIALIZED);
+ }
break;
case MEM:
tree_add_const_value_attribute (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, gc, deferred_locations_list, &entry);
+}
+
/* Helper function for tree_add_const_value_attribute. Natively encode
initializer INIT into an array. Return true if successful. */
add_name_attribute (enum_die,
IDENTIFIER_POINTER (TREE_PURPOSE (link)));
+ if (TREE_CODE (value) == CONST_DECL)
+ value = DECL_INITIAL (value);
+
if (host_integerp (value, TYPE_UNSIGNED (TREE_TYPE (value))))
/* DWARF2 does not provide a way of indicating whether or
not enumeration constants are signed or unsigned. GDB
}
+/* Returns a hash value for X (which really is a die_struct). */
+
+static hashval_t
+common_block_die_table_hash (const void *x)
+{
+ const_dw_die_ref d = (const_dw_die_ref) x;
+ return (hashval_t) d->decl_id ^ htab_hash_pointer (d->die_parent);
+}
+
+/* Return nonzero if decl_id and die_parent of die_struct X is the same
+ as decl_id and die_parent of die_struct Y. */
+
+static int
+common_block_die_table_eq (const void *x, const void *y)
+{
+ const_dw_die_ref d = (const_dw_die_ref) x;
+ const_dw_die_ref e = (const_dw_die_ref) y;
+ return d->decl_id == e->decl_id && d->die_parent == e->die_parent;
+}
+
/* Generate a DIE to represent a declared data object. */
static void
tree field;
dw_die_ref com_die;
dw_loc_descr_ref loc;
+ die_node com_die_arg;
var_die = lookup_decl_die (decl);
if (var_die)
if (loc)
{
if (off)
- add_loc_descr (&loc, new_loc_descr (DW_OP_plus_uconst,
+ {
+ /* Optimize the common case. */
+ if (loc->dw_loc_opc == DW_OP_addr
+ && loc->dw_loc_next == NULL
+ && GET_CODE (loc->dw_loc_oprnd1.v.val_addr)
+ == SYMBOL_REF)
+ loc->dw_loc_oprnd1.v.val_addr
+ = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off);
+ else
+ add_loc_descr (&loc,
+ new_loc_descr (DW_OP_plus_uconst,
off, 0));
+ }
add_AT_loc (var_die, DW_AT_location, loc);
remove_AT (var_die, DW_AT_declaration);
}
}
return;
}
+
+ if (common_block_die_table == NULL)
+ common_block_die_table
+ = htab_create_ggc (10, common_block_die_table_hash,
+ common_block_die_table_eq, NULL);
+
field = TREE_OPERAND (DECL_VALUE_EXPR (decl), 0);
- com_die = lookup_decl_die (com_decl);
+ com_die_arg.decl_id = DECL_UID (com_decl);
+ com_die_arg.die_parent = context_die;
+ com_die = (dw_die_ref) htab_find (common_block_die_table, &com_die_arg);
loc = loc_descriptor_from_tree (com_decl);
if (com_die == NULL)
{
const char *cnam
= IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (com_decl));
+ void **slot;
com_die = new_die (DW_TAG_common_block, context_die, decl);
add_name_and_src_coords_attributes (com_die, com_decl);
else if (DECL_EXTERNAL (decl))
add_AT_flag (com_die, DW_AT_declaration, 1);
add_pubname_string (cnam, com_die); /* ??? needed? */
- equate_decl_number_to_die (com_decl, com_die);
+ com_die->decl_id = DECL_UID (com_decl);
+ slot = htab_find_slot (common_block_die_table, com_die, INSERT);
+ *slot = (void *) com_die;
}
else if (get_AT (com_die, DW_AT_location) == NULL && loc)
{
if (loc)
{
if (off)
- add_loc_descr (&loc, new_loc_descr (DW_OP_plus_uconst, off, 0));
+ {
+ /* Optimize the common case. */
+ if (loc->dw_loc_opc == DW_OP_addr
+ && loc->dw_loc_next == NULL
+ && GET_CODE (loc->dw_loc_oprnd1.v.val_addr) == SYMBOL_REF)
+ loc->dw_loc_oprnd1.v.val_addr
+ = plus_constant (loc->dw_loc_oprnd1.v.val_addr, off);
+ else
+ add_loc_descr (&loc, new_loc_descr (DW_OP_plus_uconst,
+ off, 0));
+ }
add_AT_loc (var_die, DW_AT_location, loc);
}
else if (DECL_EXTERNAL (decl))
if (! declaration && ! DECL_ABSTRACT (decl))
{
- add_location_or_const_value_attribute (var_die, decl, DW_AT_location);
+ if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)
+ && !TREE_SYMBOL_REFERENCED (DECL_ASSEMBLER_NAME (decl)))
+ defer_location (decl, var_die);
+ else
+ add_location_or_const_value_attribute (var_die, decl, DW_AT_location);
add_pubname (decl, var_die);
}
else
}
-/* If STMT's abstract origin is a function declaration and STMT's
- first subblock's abstract origin is the function's outermost block,
- then we're looking at the main entry point. */
-static bool
-is_inlined_entry_point (const_tree stmt)
-{
- tree decl, block;
-
- if (!stmt || TREE_CODE (stmt) != BLOCK)
- return false;
-
- decl = block_ultimate_origin (stmt);
-
- if (!decl || TREE_CODE (decl) != FUNCTION_DECL)
- return false;
-
- block = BLOCK_SUBBLOCKS (stmt);
-
- if (block)
- {
- if (TREE_CODE (block) != BLOCK)
- return false;
-
- block = block_ultimate_origin (block);
- }
-
- return block == DECL_INITIAL (decl);
-}
-
/* A helper function for gen_lexical_block_die and gen_inlined_subroutine_die.
Add low_pc and high_pc attributes to the DIE for a block STMT. */
{
tree chain;
- if (is_inlined_entry_point (stmt))
+ if (inlined_function_outer_scope_p (stmt))
{
ASM_GENERATE_INTERNAL_LABEL (label, BLOCK_BEGIN_LABEL,
BLOCK_NUMBER (stmt));
gen_block_die (tree stmt, dw_die_ref context_die, int depth)
{
int must_output_die = 0;
- tree origin;
tree decl;
- enum tree_code origin_code;
+ bool inlined_func;
/* Ignore blocks that are NULL. */
if (stmt == NULL_TREE)
return;
+ inlined_func = inlined_function_outer_scope_p (stmt);
+
/* If the block is one fragment of a non-contiguous block, do not
process the variables, since they will have been done by the
origin block. Do process subblocks. */
return;
}
- /* Determine the "ultimate origin" of this block. This block may be an
- inlined instance of an inlined instance of inline function, so we have
- to trace all of the way back through the origin chain to find out what
- sort of node actually served as the original seed for the creation of
- the current block. */
- origin = block_ultimate_origin (stmt);
- origin_code = (origin != NULL) ? TREE_CODE (origin) : ERROR_MARK;
-
/* Determine if we need to output any Dwarf DIEs at all to represent this
block. */
- if (origin_code == FUNCTION_DECL)
+ if (inlined_func)
/* The outer scopes for inlinings *must* always be represented. We
generate DW_TAG_inlined_subroutine DIEs for them. (See below.) */
must_output_die = 1;
else
{
- /* In the case where the current block represents an inlining of the
- "body block" of an inline function, we must *NOT* output any DIE for
- this block because we have already output a DIE to represent the whole
- inlined function scope and the "body block" of any function doesn't
- really represent a different scope according to ANSI C rules. So we
- check here to make sure that this block does not represent a "body
- block inlining" before trying to set the MUST_OUTPUT_DIE flag. */
- if (! is_body_block (origin ? origin : stmt))
- {
- /* Determine if this block directly contains any "significant"
- local declarations which we will need to output DIEs for. */
- if (debug_info_level > DINFO_LEVEL_TERSE)
- /* We are not in terse mode so *any* local declaration counts
- as being a "significant" one. */
- must_output_die = (BLOCK_VARS (stmt) != NULL
- && (TREE_USED (stmt)
- || TREE_ASM_WRITTEN (stmt)
- || BLOCK_ABSTRACT (stmt)));
- else
- /* We are in terse mode, so only local (nested) function
- definitions count as "significant" local declarations. */
- for (decl = BLOCK_VARS (stmt);
- decl != NULL; decl = TREE_CHAIN (decl))
- if (TREE_CODE (decl) == FUNCTION_DECL
- && DECL_INITIAL (decl))
- {
- must_output_die = 1;
- break;
- }
- }
+ /* Determine if this block directly contains any "significant"
+ local declarations which we will need to output DIEs for. */
+ if (debug_info_level > DINFO_LEVEL_TERSE)
+ /* We are not in terse mode so *any* local declaration counts
+ as being a "significant" one. */
+ must_output_die = (BLOCK_VARS (stmt) != NULL
+ && (TREE_USED (stmt)
+ || TREE_ASM_WRITTEN (stmt)
+ || BLOCK_ABSTRACT (stmt)));
+ else
+ /* We are in terse mode, so only local (nested) function
+ definitions count as "significant" local declarations. */
+ for (decl = BLOCK_VARS (stmt);
+ decl != NULL; decl = TREE_CHAIN (decl))
+ if (TREE_CODE (decl) == FUNCTION_DECL
+ && DECL_INITIAL (decl))
+ {
+ must_output_die = 1;
+ break;
+ }
}
/* It would be a waste of space to generate a Dwarf DW_TAG_lexical_block
instances and local (nested) function definitions. */
if (must_output_die)
{
- if (origin_code == FUNCTION_DECL)
+ if (inlined_func)
gen_inlined_subroutine_die (stmt, context_die, depth);
else
gen_lexical_block_die (stmt, context_die, depth);
if (die != NULL && die->die_parent == NULL)
add_child_die (context_die, die);
- /* Do not produce debug information for static variables since
- these might be optimized out. We are called for these later
- in varpool_analyze_pending_decls.
-
- But *do* produce it for Fortran COMMON variables because,
- even though they are static, their names can differ depending
- on the scope, which we need to preserve. */
- if (TREE_CODE (decl) == VAR_DECL && TREE_STATIC (decl)
- && !(is_fortran () && TREE_PUBLIC (decl)))
- ;
+ else if (TREE_CODE (decl) == IMPORTED_DECL)
+ dwarf2out_imported_module_or_decl_1 (decl, DECL_NAME (decl),
+ stmt, context_die);
else
gen_decl_die (decl, context_die);
}
break;
case NAMESPACE_DECL:
+ case IMPORTED_DECL:
gen_namespace_die (decl);
break;
}
/* Output debug information for imported module or decl DECL.
- NAME is non-NULL name in context if the decl has been renamed.
- CHILD is true if decl is one of the renamed decls as part of
- importing whole module. */
-
+ NAME is non-NULL name in the lexical block if the decl has been renamed.
+ LEXICAL_BLOCK is the lexical block (which TREE_CODE is a BLOCK)
+ that DECL belongs to.
+ LEXICAL_BLOCK_DIE is the DIE of LEXICAL_BLOCK. */
static void
-dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
- bool child)
+dwarf2out_imported_module_or_decl_1 (tree decl,
+ tree name,
+ tree lexical_block,
+ dw_die_ref lexical_block_die)
{
- dw_die_ref imported_die, at_import_die;
- dw_die_ref scope_die;
expanded_location xloc;
+ dw_die_ref imported_die = NULL;
+ dw_die_ref at_import_die;
- if (debug_info_level <= DINFO_LEVEL_TERSE)
- return;
-
- gcc_assert (decl);
-
- /* 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. */
-
- /* Get the scope die for decl context. Use comp_unit_die for global module
- or decl. If die is not found for non globals, force new die. */
- if (context
- && TYPE_P (context)
- && !should_emit_struct_debug (context, DINFO_USAGE_DIR_USE))
- return;
- scope_die = get_context_die (context);
-
- if (child)
- {
- gcc_assert (scope_die->die_child);
- gcc_assert (scope_die->die_child->die_tag == DW_TAG_imported_module);
- gcc_assert (TREE_CODE (decl) != NAMESPACE_DECL);
- scope_die = scope_die->die_child;
- }
-
- /* For TYPE_DECL or CONST_DECL, lookup TREE_TYPE. */
if (TREE_CODE (decl) == TYPE_DECL || TREE_CODE (decl) == CONST_DECL)
{
if (is_base_type (TREE_TYPE (decl)))
gcc_assert (at_import_die);
}
}
+ else if (TREE_CODE (decl) == IMPORTED_DECL)
+ {
+ tree imported_ns_decl;
+ /* IMPORTED_DECL nodes that are not imported namespace are just not
+ supported yet. */
+ gcc_assert (DECL_INITIAL (decl)
+ && TREE_CODE (DECL_INITIAL (decl)) == NAMESPACE_DECL);
+ imported_ns_decl = DECL_INITIAL (decl);
+ at_import_die = lookup_decl_die (imported_ns_decl);
+ if (!at_import_die)
+ at_import_die = force_decl_die (imported_ns_decl);
+ gcc_assert (at_import_die);
+ }
else
{
at_import_die = lookup_decl_die (decl);
}
}
- /* OK, now we have DIEs for decl as well as scope. Emit imported die. */
if (TREE_CODE (decl) == NAMESPACE_DECL)
- imported_die = new_die (DW_TAG_imported_module, scope_die, context);
+ imported_die = new_die (DW_TAG_imported_module,
+ lexical_block_die,
+ lexical_block);
else
- imported_die = new_die (DW_TAG_imported_declaration, scope_die, context);
+ imported_die = new_die (DW_TAG_imported_declaration,
+ lexical_block_die,
+ lexical_block);
xloc = expand_location (input_location);
add_AT_file (imported_die, DW_AT_decl_file, lookup_filename (xloc.file));
add_AT_unsigned (imported_die, DW_AT_decl_line, xloc.line);
if (name)
- add_AT_string (imported_die, DW_AT_name, IDENTIFIER_POINTER (name));
+ add_AT_string (imported_die, DW_AT_name,
+ IDENTIFIER_POINTER (name));
add_AT_die_ref (imported_die, DW_AT_import, at_import_die);
}
+/* Output debug information for imported module or decl DECL.
+ NAME is non-NULL name in context if the decl has been renamed.
+ CHILD is true if decl is one of the renamed decls as part of
+ importing whole module. */
+
+static void
+dwarf2out_imported_module_or_decl (tree decl, tree name, tree context,
+ bool child)
+{
+ /* dw_die_ref at_import_die; */
+ dw_die_ref scope_die;
+
+ if (debug_info_level <= DINFO_LEVEL_TERSE)
+ return;
+
+ gcc_assert (decl);
+
+ /* 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. */
+
+ /* Get the scope die for decl context. Use comp_unit_die for global module
+ or decl. If die is not found for non globals, force new die. */
+ if (context
+ && TYPE_P (context)
+ && !should_emit_struct_debug (context, DINFO_USAGE_DIR_USE))
+ return;
+ scope_die = get_context_die (context);
+
+ if (child)
+ {
+ gcc_assert (scope_die->die_child);
+ gcc_assert (scope_die->die_child->die_tag == DW_TAG_imported_module);
+ gcc_assert (TREE_CODE (decl) != NAMESPACE_DECL);
+ scope_die = scope_die->die_child;
+ }
+
+ /* 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);
+
+}
+
/* Write the debugging output for DECL. */
void
break;
case NAMESPACE_DECL:
+ case IMPORTED_DECL:
if (debug_info_level <= DINFO_LEVEL_TERSE)
return;
if (lookup_decl_die (decl) != NULL)
}
}
+/* For local classes, look if any static member functions were emitted
+ and if so, mark them. */
+
+static void
+prune_unused_types_walk_local_classes (dw_die_ref die)
+{
+ dw_die_ref c;
+
+ if (die->die_mark == 2)
+ return;
+
+ switch (die->die_tag)
+ {
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ break;
+
+ case DW_TAG_subprogram:
+ if (!get_AT_flag (die, DW_AT_declaration)
+ || die->die_definition != NULL)
+ prune_unused_types_mark (die, 1);
+ return;
+
+ default:
+ return;
+ }
+
+ /* Mark children. */
+ FOR_EACH_CHILD (die, c, prune_unused_types_walk_local_classes (c));
+}
/* Walk the tree DIE and mark types that we actually use. */
{
dw_die_ref c;
- /* Don't do anything if this node is already marked. */
- if (die->die_mark)
+ /* Don't do anything if this node is already marked and
+ children have been marked as well. */
+ if (die->die_mark == 2)
return;
switch (die->die_tag)
{
+ case DW_TAG_structure_type:
+ case DW_TAG_union_type:
+ case DW_TAG_class_type:
+ if (die->die_perennial_p)
+ break;
+
+ for (c = die->die_parent; c; c = c->die_parent)
+ if (c->die_tag == DW_TAG_subprogram)
+ break;
+
+ /* Finding used static member functions inside of classes
+ is needed just for local classes, because for other classes
+ static member function DIEs with DW_AT_specification
+ are emitted outside of the DW_TAG_*_type. If we ever change
+ it, we'd need to call this even for non-local classes. */
+ if (c)
+ prune_unused_types_walk_local_classes (die);
+
+ /* It's a type node --- don't mark it. */
+ return;
+
case DW_TAG_const_type:
case DW_TAG_packed_type:
case DW_TAG_pointer_type:
case DW_TAG_volatile_type:
case DW_TAG_typedef:
case DW_TAG_array_type:
- case DW_TAG_structure_type:
- case DW_TAG_union_type:
- case DW_TAG_class_type:
case DW_TAG_interface_type:
case DW_TAG_friend:
case DW_TAG_variant_part:
break;
}
- die->die_mark = 1;
+ if (die->die_mark == 0)
+ {
+ die->die_mark = 1;
- /* Now, mark any dies referenced from here. */
- prune_unused_types_walk_attribs (die);
+ /* Now, mark any dies referenced from here. */
+ prune_unused_types_walk_attribs (die);
+ }
+
+ die->die_mark = 2;
/* Mark children. */
FOR_EACH_CHILD (die, c, prune_unused_types_walk (c));
{
limbo_die_node *node, *next_node;
dw_die_ref die = 0;
+ unsigned int i;
/* Add the name for the main input file now. We delayed this from
dwarf2out_init to avoid complications with PCH. */
add_comp_dir_attribute (comp_unit_die);
}
+ for (i = 0; i < VEC_length (deferred_locations, deferred_locations_list); i++)
+ {
+ add_location_or_const_value_attribute (
+ VEC_index (deferred_locations, deferred_locations_list, i)->die,
+ VEC_index (deferred_locations, deferred_locations_list, i)->variable,
+ 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 (node = limbo_die_list; node; node = node->next)
output_comp_unit (node->die, 0);
- output_comp_unit (comp_unit_die, 0);
+ /* Output the main compilation unit if non-empty or if .debug_macinfo
+ has been emitted. */
+ output_comp_unit (comp_unit_die, debug_info_level >= DINFO_LEVEL_VERBOSE);
/* Output the abbreviation table. */
switch_to_section (debug_abbrev_section);