diff mbox

Enhance array types debug info. for Ada

Message ID 547C8941.2080607@adacore.com
State New
Headers show

Commit Message

Pierre-Marie de Rodat Dec. 1, 2014, 3:29 p.m. UTC
On 11/26/2014 06:42 PM, Jakub Jelinek wrote:
> Replace implicitely with implicitly in the whole patch.

Oops! Done.

>> +   If CONTEXT is NULL, the behavior is the same as if the context_type field
>> +   was NULL_TREE.  */
>
> as if both context_type and base_decl were NULL_TREE?

Absolutely: done.

>> +  if (context != NULL
>> +      && context->base_decl == loc
>> +      && want_address == 0)
>> +    return new_loc_list (new_loc_descr (DW_OP_push_object_address, 0, 0),
>> +			 NULL, NULL, NULL);
>> +
>
> This isn't guarded with dwarf_version >= 3 || !dwarf_strict.  Shouldn't it
> be too and return NULL otherwise?

Yes it should: I added this guard.

>> +	expansion_failed (loc, NULL_RTX,
>> +			  "PLACEHOLDER_EXPR for a unexpected type");
>
> for an unexpected type?

Yes: placeholder expressions are supposed only to refer to the type 
allowed by the context. I updated the message to talk about the context 
and I added another one for the (invalid) case when want_address == 0.

> Formatting.  Should use tabs, not spaces.
> [...]
> Formatting.  || should be below p in prec.

Fixed. Thank you for the review.

> Would be nice if you tried more than one fortran testcase, say build
> all gfortran.dg/ tests with -O0 -g -dA (and perhaps -O2 -g -dA afterwards)
> with both unpatched and patched compilers and diff *.s files?
>
> Otherwise, LGTM.

That was a very good idea: thanks to these diffs I realized that in 
add_scalar_info, a "return" statement got lost in the process of porting 
my patches to trunk. This caused duplication of scalar constant 
attributes in the output debugging information.

Beyond this, I checked diffs for -O0, -O1 and -O2 (each one with -g 
-dA). Trying to skip all the noise caused by the changes of DIE 
offsets/abbreviation numbers, the only significant changes I could find 
look legitimate:

   - Volatile array types used not to be described as such: after my 
patches they are wrapped in DW_TAG_volatile_type DIEs.

   - DW_AT_{lower,upper}_bound attributes are now encoded as 
DW_FORM_sdata (i.e. SLEB128) instead of as DW_FORM_data1/2/4/8. This is 
a clear win for negative ones.

I attached the only updated patch. The new patch set bootstrapped well 
and was successfully regtested on x86_64-linux.

Thank you,

Comments

Jakub Jelinek Dec. 1, 2014, 3:37 p.m. UTC | #1
On Mon, Dec 01, 2014 at 04:29:05PM +0100, Pierre-Marie de Rodat wrote:
> >>+	expansion_failed (loc, NULL_RTX,
> >>+			  "PLACEHOLDER_EXPR for a unexpected type");
> >
> >for an unexpected type?
> 
> Yes: placeholder expressions are supposed only to refer to the type allowed
> by the context. I updated the message to talk about the context and I added
> another one for the (invalid) case when want_address == 0.

I meant that you wrote "a" rather than "an".

> Beyond this, I checked diffs for -O0, -O1 and -O2 (each one with -g -dA).
> Trying to skip all the noise caused by the changes of DIE
> offsets/abbreviation numbers, the only significant changes I could find look
> legitimate:
> 
>   - Volatile array types used not to be described as such: after my patches
> they are wrapped in DW_TAG_volatile_type DIEs.

Guess that is ok.

>   - DW_AT_{lower,upper}_bound attributes are now encoded as DW_FORM_sdata
> (i.e. SLEB128) instead of as DW_FORM_data1/2/4/8. This is a clear win for
> negative ones.

That might be a compatibility issue for older debuggers, especially for the
strict dwarf cases.  Where does this difference come from?  Why doesn't

> +      /* If HOST_WIDE_INT is big enough then represent the bound as
> +	 a constant value.  We need to choose a form based on
> +	 whether the type is signed or unsigned.  We cannot just
> +	 call add_AT_unsigned if the value itself is positive
> +	 (add_AT_unsigned might add the unsigned value encoded as
> +	 DW_FORM_data[1248]).  Some DWARF consumers will lookup the
> +	 bounds type and then sign extend any unsigned values found
> +	 for signed types.  This is needed only for
> +	 DW_AT_{lower,upper}_bound, since for most other attributes,
> +	 consumers will treat DW_FORM_data[1248] as unsigned values,
> +	 regardless of the underlying type.  */
> +      if (prec <= HOST_BITS_PER_WIDE_INT
> +	  || tree_fits_uhwi_p (value))
> +	{
> +	  if (TYPE_UNSIGNED (TREE_TYPE (value)))
> +	    add_AT_unsigned (die, attr, TREE_INT_CST_LOW (value));
> +	  else
> +	    add_AT_int (die, attr, TREE_INT_CST_LOW (value));
> +	}
> +      else
> +	/* Otherwise represent the bound as an unsigned value with
> +	   the precision of its type.  The precision and signedness
> +	   of the type will be necessary to re-interpret it
> +	   unambiguously.  */
> +	add_AT_wide (die, attr, value);

handle it the same as it used to?  Unconditional DW_FORM_sdata is certainly
not a size win for various values...

	Jakub
Pierre-Marie de Rodat Dec. 1, 2014, 4:40 p.m. UTC | #2
On 12/01/2014 04:37 PM, Jakub Jelinek wrote:
>>> for an unexpected type?
>>
>> Yes: placeholder expressions are supposed only to refer to the type allowed
>> by the context. I updated the message to talk about the context and I added
>> another one for the (invalid) case when want_address == 0.
>
> I meant that you wrote "a" rather than "an".

Argh, sorry! ;-) Back to the simple and fixed version.

>>    - DW_AT_{lower,upper}_bound attributes are now encoded as DW_FORM_sdata
>> (i.e. SLEB128) instead of as DW_FORM_data1/2/4/8. This is a clear win for
>> negative ones.
>
> That might be a compatibility issue for older debuggers, especially for the
> strict dwarf cases.  Where does this difference come from?  Why doesn't
> [...]
>> +	    add_AT_unsigned (die, attr, TREE_INT_CST_LOW (value));
>> +	  else
>> +	    add_AT_int (die, attr, TREE_INT_CST_LOW (value));
> [...]
> handle it the same as it used to?  Unconditional DW_FORM_sdata is certainly
> not a size win for various values...

No, indeed: there are few positive values for which DW_FORM_sdata is one 
byte longer than the shortest appropriate DW_FORM_data1/2/4/8. However 
having different forms for the same attribute will generate as many 
abbreviations. I'm not sure how to balance what is best...

Besides if I understand correctly, the behavior of the code above has 
not changed. Instead, the array language hook used to call 
add_descr_info_field which itself used to call add_AT_unsigned even for 
signed types (instead of add_AT_int as above). Looking at add_AT_int and 
size_of_die, it looks like signed types are always encoded in SLEB128 in 
the "regular circuitry".

While I agree this might trigger compatibility issues with old 
debuggers, I don't know what to do assuming this change is not 
acceptable: should we add a kludge in add_scalar_info in order to force 
unsignedness when generating debugging information for Fortran?
Pierre-Marie de Rodat Dec. 15, 2014, 4:21 p.m. UTC | #3
Ping for https://gcc.gnu.org/ml/gcc-patches/2014-12/msg00058.html.

On 12/01/2014 05:40 PM, Pierre-Marie de Rodat wrote:
> While I agree this might trigger compatibility issues with old
> debuggers, I don't know what to do assuming this change is not
> acceptable: should we add a kludge in add_scalar_info in order to force
> unsignedness when generating debugging information for Fortran?

Here is a data point: I tried to debug gfortran.dg/array_function_2.f90 
build with my patches compiler for x86_64-linux with a GDB from an old 
GNAT Pro release (5.03a1, from 2005):

(gdb) b array_function_2.f90:24
(gdb) r
(gdb) ptype q_in
type = real*8 (0:-1,-6:-1)

With a recent GDB, I have instead:
(gdb) ptype q_in
type = real(kind=8) (0:*,-6:*)

Given that the only thing that my patches changed in the debug 
information for this example is the encoding of the arrays' lower 
bounds, everything looks fine, here.
Jakub Jelinek Dec. 15, 2014, 4:24 p.m. UTC | #4
On Mon, Dec 15, 2014 at 05:21:07PM +0100, Pierre-Marie de Rodat wrote:
> Ping for https://gcc.gnu.org/ml/gcc-patches/2014-12/msg00058.html.

Ok for trunk then.

> On 12/01/2014 05:40 PM, Pierre-Marie de Rodat wrote:
> >While I agree this might trigger compatibility issues with old
> >debuggers, I don't know what to do assuming this change is not
> >acceptable: should we add a kludge in add_scalar_info in order to force
> >unsignedness when generating debugging information for Fortran?
> 
> Here is a data point: I tried to debug gfortran.dg/array_function_2.f90
> build with my patches compiler for x86_64-linux with a GDB from an old GNAT
> Pro release (5.03a1, from 2005):
> 
> (gdb) b array_function_2.f90:24
> (gdb) r
> (gdb) ptype q_in
> type = real*8 (0:-1,-6:-1)
> 
> With a recent GDB, I have instead:
> (gdb) ptype q_in
> type = real(kind=8) (0:*,-6:*)
> 
> Given that the only thing that my patches changed in the debug information
> for this example is the encoding of the arrays' lower bounds, everything
> looks fine, here.
> 
> -- 
> Pierre-Marie de Rodat

	Jakub
Pierre-Marie de Rodat Dec. 17, 2014, 4:27 p.m. UTC | #5
On 12/15/2014 05:24 PM, Jakub Jelinek wrote:
> Ok for trunk then.

All the 5 commits are submitted. Thank you very much for your review! :-)
diff mbox

Patch

From 4a8fe9204873864fd7ac898622d09a1d60bcea6b Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <derodat@adacore.com>
Date: Mon, 9 Jun 2014 15:13:45 +0200
Subject: [PATCH 5/5] dwarf2out.c: do not short-circuit add_bound_info in
 array descr. lang-hook

gcc/
	* dwarf2out.h (struct array_descr_info): Remove the base_decl field.
	* dwarf2out.c (enum dw_scalar_form): New.
	(struct loc_descr_context): New.
	(add_scalar_info): New.
	(add_bound_info): Add a context parameter.  Use add_scalar_info.
	(loc_list_from_tree): Add a context parameter.  Handle PLACEHOLDER_EXPR
	nodes for type-related expressions.  Likewise for base declarations.
	(loc_descriptor_from_tree): Add a context parameter.
	(subrange_type_die): Update calls to add_bound_info.
	(tls_mem_loc_descriptor): Likewise.
	(loc_list_for_address_of_addr_expr_of_indirect_ref): Add a context
	parameter.  Update calls to loc_list_from_tree.
	(add_subscript_info): Update calls to add_bound_info.
	(gen_array_type_die): Update calls to loc_list_from_tree and to
	add_bound_info.
	(descr_info_loc): Remove.
	(add_descr_info_field): Remove.
	(gen_descr_array_type_die): Switch add_descr_info_field calls into
	add_scalar_info/add_bound_info ones.
	(gen_subprogram_die): Update calls to loc_list_from_tree.
	(gen_variable_die): Likewise.
---
 gcc/dwarf2out.c |  574 +++++++++++++++++++++++++++++--------------------------
 1 file changed, 299 insertions(+), 275 deletions(-)

diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 4d6da4b..115eaa2 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -3029,6 +3029,15 @@  static bool frame_pointer_fb_offset_valid;
 
 static vec<dw_die_ref> base_types;
 
+/* Flags to represent a set of attribute classes for attributes that represent
+   a scalar value (bounds, pointers, ...).  */
+enum dw_scalar_form
+{
+  dw_scalar_form_constant = 0x01,
+  dw_scalar_form_exprloc = 0x02,
+  dw_scalar_form_reference = 0x04
+};
+
 /* Forward declarations for functions defined in this file.  */
 
 static int is_pseudo_reg (const_rtx);
@@ -3203,8 +3212,11 @@  static dw_loc_descr_ref concat_loc_descriptor (rtx, rtx,
 					       enum var_init_status);
 static dw_loc_descr_ref loc_descriptor (rtx, machine_mode mode,
 					enum var_init_status);
-static dw_loc_list_ref loc_list_from_tree (tree, int);
-static dw_loc_descr_ref loc_descriptor_from_tree (tree, int);
+struct loc_descr_context;
+static dw_loc_list_ref loc_list_from_tree (tree, int,
+					   const struct loc_descr_context *);
+static dw_loc_descr_ref loc_descriptor_from_tree (tree, int,
+						  const struct loc_descr_context *);
 static HOST_WIDE_INT ceiling (HOST_WIDE_INT, unsigned int);
 static tree field_type (const_tree);
 static unsigned int simple_type_align_in_bits (const_tree);
@@ -3226,7 +3238,10 @@  static bool tree_add_const_value_attribute_for_decl (dw_die_ref, tree);
 static void add_name_attribute (dw_die_ref, const char *);
 static void add_gnat_descriptive_type_attribute (dw_die_ref, tree, dw_die_ref);
 static void add_comp_dir_attribute (dw_die_ref);
-static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree);
+static void add_scalar_info (dw_die_ref, enum dwarf_attribute, tree, int,
+			     const struct loc_descr_context *);
+static void add_bound_info (dw_die_ref, enum dwarf_attribute, tree,
+			    const struct loc_descr_context *);
 static void add_subscript_info (dw_die_ref, tree, bool);
 static void add_byte_size_attribute (dw_die_ref, tree);
 static void add_bit_offset_attribute (dw_die_ref, tree);
@@ -10556,9 +10571,9 @@  subrange_type_die (tree type, tree low, tree high, dw_die_ref context_die)
     }
 
   if (low)
-    add_bound_info (subrange_die, DW_AT_lower_bound, low);
+    add_bound_info (subrange_die, DW_AT_lower_bound, low, NULL);
   if (high)
-    add_bound_info (subrange_die, DW_AT_upper_bound, high);
+    add_bound_info (subrange_die, DW_AT_upper_bound, high, NULL);
 
   return subrange_die;
 }
@@ -11534,7 +11549,7 @@  tls_mem_loc_descriptor (rtx mem)
       || !DECL_THREAD_LOCAL_P (base))
     return NULL;
 
-  loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1);
+  loc_result = loc_descriptor_from_tree (MEM_EXPR (mem), 1, NULL);
   if (loc_result == NULL)
     return NULL;
 
@@ -14272,10 +14287,13 @@  cst_pool_loc_descr (tree loc)
 
 /* Return dw_loc_list representing address of addr_expr LOC
    by looking for inner INDIRECT_REF expression and turning
-   it into simple arithmetics.  */
+   it into simple arithmetics.
+
+   See loc_list_from_tree for the meaning of CONTEXT.  */
 
 static dw_loc_list_ref
-loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev)
+loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev,
+						   const loc_descr_context *context)
 {
   tree obj, offset;
   HOST_WIDE_INT bitsize, bitpos, bytepos;
@@ -14299,18 +14317,19 @@  loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev)
       return 0;
     }
   if (!offset && !bitpos)
-    list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1);
+    list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), toplev ? 2 : 1,
+				   context);
   else if (toplev
 	   && int_size_in_bytes (TREE_TYPE (loc)) <= DWARF2_ADDR_SIZE
 	   && (dwarf_version >= 4 || !dwarf_strict))
     {
-      list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0);
+      list_ret = loc_list_from_tree (TREE_OPERAND (obj, 0), 0, context);
       if (!list_ret)
 	return 0;
       if (offset)
 	{
 	  /* Variable offset.  */
-	  list_ret1 = loc_list_from_tree (offset, 0);
+	  list_ret1 = loc_list_from_tree (offset, 0, context);
 	  if (list_ret1 == 0)
 	    return 0;
 	  add_loc_list (&list_ret, list_ret1);
@@ -14333,15 +14352,36 @@  loc_list_for_address_of_addr_expr_of_indirect_ref (tree loc, bool toplev)
 }
 
 
+/* Helper structure for location descriptions generation.  */
+struct loc_descr_context
+{
+  /* The type that is implicitly referenced by DW_OP_push_object_address, or
+     NULL_TREE if DW_OP_push_object_address in invalid for this location
+     description.  This is used when processing PLACEHOLDER_EXPR nodes.  */
+  tree context_type;
+  /* The ..._DECL node that should be translated as a
+     DW_OP_push_object_address operation.  */
+  tree base_decl;
+};
+
 /* Generate Dwarf location list representing LOC.
    If WANT_ADDRESS is false, expression computing LOC will be computed
    If WANT_ADDRESS is 1, expression computing address of LOC will be returned
    if WANT_ADDRESS is 2, expression computing address useable in location
      will be returned (i.e. DW_OP_reg can be used
-     to refer to register values).  */
+     to refer to register values).
+
+   CONTEXT provides information to customize the location descriptions
+   generation.  Its context_type field specifies what type is implicitly
+   referenced by DW_OP_push_object_address.  If it is NULL_TREE, this operation
+   will not be generated.
+
+   If CONTEXT is NULL, the behavior is the same as if both context_type and
+   base_decl fields were NULL_TREE.  */
 
 static dw_loc_list_ref
-loc_list_from_tree (tree loc, int want_address)
+loc_list_from_tree (tree loc, int want_address,
+		    const struct loc_descr_context *context)
 {
   dw_loc_descr_ref ret = NULL, ret1 = NULL;
   dw_loc_list_ref list_ret = NULL, list_ret1 = NULL;
@@ -14352,6 +14392,17 @@  loc_list_from_tree (tree loc, int want_address)
      extending the values properly.  Hopefully this won't be a real
      problem...  */
 
+  if (context != NULL
+      && context->base_decl == loc
+      && want_address == 0)
+    {
+      if (dwarf_version >= 3 || !dwarf_strict)
+	return new_loc_list (new_loc_descr (DW_OP_push_object_address, 0, 0),
+			     NULL, NULL, NULL);
+      else
+	return NULL;
+    }
+
   switch (TREE_CODE (loc))
     {
     case ERROR_MARK:
@@ -14360,11 +14411,25 @@  loc_list_from_tree (tree loc, int want_address)
 
     case PLACEHOLDER_EXPR:
       /* This case involves extracting fields from an object to determine the
-	 position of other fields.  We don't try to encode this here.  The
-	 only user of this is Ada, which encodes the needed information using
-	 the names of types.  */
-      expansion_failed (loc, NULL_RTX, "PLACEHOLDER_EXPR");
-      return 0;
+	 position of other fields. It is supposed to appear only as the first
+	 operand of COMPONENT_REF nodes and to reference precisely the type
+	 that the context allows.  */
+      if (context == NULL || TREE_TYPE (loc) == context->context_type)
+	expansion_failed (loc, NULL_RTX,
+			  "PLACEHOLDER_EXPR in invalid context");
+      else if (want_address == 0)
+	expansion_failed (loc, NULL_RTX,
+			  "Want value of PLACEHOLDER_EXPR:"
+			  " only address is valid");
+      else if (dwarf_version >= 3 || !dwarf_strict)
+	{
+	  ret = new_loc_descr (DW_OP_push_object_address, 0, 0);
+	  have_address = 1;
+	  break;
+	}
+      else
+	return NULL;
+      break;
 
     case CALL_EXPR:
       expansion_failed (loc, NULL_RTX, "CALL_EXPR");
@@ -14385,7 +14450,7 @@  loc_list_from_tree (tree loc, int want_address)
       if (want_address)
 	{
 	  list_ret = loc_list_for_address_of_addr_expr_of_indirect_ref
-		       (loc, want_address == 2);
+		       (loc, want_address == 2, context);
 	  if (list_ret)
 	    have_address = 1;
 	  else if (decl_address_ip_invariant_p (TREE_OPERAND (loc, 0))
@@ -14394,7 +14459,7 @@  loc_list_from_tree (tree loc, int want_address)
 	}
         /* Otherwise, process the argument and look for the address.  */
       if (!list_ret && !ret)
-        list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1);
+        list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 1, context);
       else
 	{
 	  if (want_address)
@@ -14464,7 +14529,7 @@  loc_list_from_tree (tree loc, int want_address)
     case RESULT_DECL:
       if (DECL_HAS_VALUE_EXPR_P (loc))
 	return loc_list_from_tree (DECL_VALUE_EXPR (loc),
-				   want_address);
+				   want_address, context);
       /* FALLTHRU */
 
     case FUNCTION_DECL:
@@ -14538,7 +14603,7 @@  loc_list_from_tree (tree loc, int want_address)
 	}
       /* Fallthru.  */
     case INDIRECT_REF:
-      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
       have_address = 1;
       break;
 
@@ -14547,13 +14612,13 @@  loc_list_from_tree (tree loc, int want_address)
       return NULL;
 
     case COMPOUND_EXPR:
-      return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address);
+      return loc_list_from_tree (TREE_OPERAND (loc, 1), want_address, context);
 
     CASE_CONVERT:
     case VIEW_CONVERT_EXPR:
     case SAVE_EXPR:
     case MODIFY_EXPR:
-      return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address);
+      return loc_list_from_tree (TREE_OPERAND (loc, 0), want_address, context);
 
     case COMPONENT_REF:
     case BIT_FIELD_REF:
@@ -14574,7 +14639,8 @@  loc_list_from_tree (tree loc, int want_address)
 
 	list_ret = loc_list_from_tree (obj,
 				       want_address == 2
-				       && !bitpos && !offset ? 2 : 1);
+				       && !bitpos && !offset ? 2 : 1,
+				       context);
 	/* TODO: We can extract value of the small expression via shifting even
 	   for nonzero bitpos.  */
 	if (list_ret == 0)
@@ -14589,7 +14655,7 @@  loc_list_from_tree (tree loc, int want_address)
 	if (offset != NULL_TREE)
 	  {
 	    /* Variable offset.  */
-	    list_ret1 = loc_list_from_tree (offset, 0);
+	    list_ret1 = loc_list_from_tree (offset, 0, context);
 	    if (list_ret1 == 0)
 	      return 0;
 	    add_loc_list (&list_ret, list_ret1);
@@ -14679,8 +14745,8 @@  loc_list_from_tree (tree loc, int want_address)
 	  op = DW_OP_mod;
 	  goto do_binop;
 	}
-      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
-      list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0);
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
+      list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0, context);
       if (list_ret == 0 || list_ret1 == 0)
 	return 0;
 
@@ -14711,7 +14777,7 @@  loc_list_from_tree (tree loc, int want_address)
     do_plus:
       if (tree_fits_shwi_p (TREE_OPERAND (loc, 1)))
 	{
-	  list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+	  list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
 	  if (list_ret == 0)
 	    return 0;
 
@@ -14759,8 +14825,8 @@  loc_list_from_tree (tree loc, int want_address)
       goto do_binop;
 
     do_binop:
-      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
-      list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0);
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
+      list_ret1 = loc_list_from_tree (TREE_OPERAND (loc, 1), 0, context);
       if (list_ret == 0 || list_ret1 == 0)
 	return 0;
 
@@ -14784,7 +14850,7 @@  loc_list_from_tree (tree loc, int want_address)
       goto do_unop;
 
     do_unop:
-      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+      list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
       if (list_ret == 0)
 	return 0;
 
@@ -14808,12 +14874,12 @@  loc_list_from_tree (tree loc, int want_address)
     case COND_EXPR:
       {
 	dw_loc_descr_ref lhs
-	  = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0);
+	  = loc_descriptor_from_tree (TREE_OPERAND (loc, 1), 0, context);
 	dw_loc_list_ref rhs
-	  = loc_list_from_tree (TREE_OPERAND (loc, 2), 0);
+	  = loc_list_from_tree (TREE_OPERAND (loc, 2), 0, context);
 	dw_loc_descr_ref bra_node, jump_node, tmp;
 
-	list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0);
+	list_ret = loc_list_from_tree (TREE_OPERAND (loc, 0), 0, context);
 	if (list_ret == 0 || lhs == 0 || rhs == 0)
 	  return 0;
 
@@ -14919,9 +14985,10 @@  loc_list_from_tree (tree loc, int want_address)
 
 /* Same as above but return only single location expression.  */
 static dw_loc_descr_ref
-loc_descriptor_from_tree (tree loc, int want_address)
+loc_descriptor_from_tree (tree loc, int want_address,
+			  const struct loc_descr_context *context)
 {
-  dw_loc_list_ref ret = loc_list_from_tree (loc, want_address);
+  dw_loc_list_ref ret = loc_list_from_tree (loc, want_address, context);
   if (!ret)
     return NULL;
   if (ret->dw_loc_next)
@@ -15979,7 +16046,8 @@  add_location_or_const_value_attribute (dw_die_ref die, tree decl, bool cache_p,
     }
   if (list == NULL)
     {
-      list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2);
+      list = loc_list_from_tree (decl, decl_by_reference_p (decl) ? 0 : 2,
+				 NULL);
       /* It is usually worth caching this result if the decl is from
 	 BLOCK_NONLOCALIZED_VARS and if the list has at least two elements.  */
       if (cache_p && list && list->dw_loc_next)
@@ -16473,6 +16541,143 @@  add_comp_dir_attribute (dw_die_ref die)
     add_AT_string (die, DW_AT_comp_dir, wd);
 }
 
+/* Given a tree node VALUE describing a scalar attribute ATTR (i.e. a bound, a
+   pointer computation, ...), output a representation for that bound according
+   to the accepted FORMS (see enum dw_scalar_form) and add it to DIE.  See
+   loc_list_from_tree for the meaning of CONTEXT.  */
+
+static void
+add_scalar_info (dw_die_ref die, enum dwarf_attribute attr, tree value,
+		 int forms, const struct loc_descr_context *context)
+{
+  dw_die_ref ctx, decl_die;
+  dw_loc_list_ref list;
+
+  bool strip_conversions = true;
+
+  while (strip_conversions)
+    switch (TREE_CODE (value))
+      {
+      case ERROR_MARK:
+      case SAVE_EXPR:
+	return;
+
+      CASE_CONVERT:
+      case VIEW_CONVERT_EXPR:
+	value = TREE_OPERAND (value, 0);
+	break;
+
+      default:
+	strip_conversions = false;
+	break;
+      }
+
+  /* If possible and permitted, output the attribute as a constant.  */
+  if ((forms & dw_scalar_form_constant) != 0
+      && TREE_CODE (value) == INTEGER_CST)
+    {
+      unsigned int prec = simple_type_size_in_bits (TREE_TYPE (value));
+
+      /* If HOST_WIDE_INT is big enough then represent the bound as
+	 a constant value.  We need to choose a form based on
+	 whether the type is signed or unsigned.  We cannot just
+	 call add_AT_unsigned if the value itself is positive
+	 (add_AT_unsigned might add the unsigned value encoded as
+	 DW_FORM_data[1248]).  Some DWARF consumers will lookup the
+	 bounds type and then sign extend any unsigned values found
+	 for signed types.  This is needed only for
+	 DW_AT_{lower,upper}_bound, since for most other attributes,
+	 consumers will treat DW_FORM_data[1248] as unsigned values,
+	 regardless of the underlying type.  */
+      if (prec <= HOST_BITS_PER_WIDE_INT
+	  || tree_fits_uhwi_p (value))
+	{
+	  if (TYPE_UNSIGNED (TREE_TYPE (value)))
+	    add_AT_unsigned (die, attr, TREE_INT_CST_LOW (value));
+	  else
+	    add_AT_int (die, attr, TREE_INT_CST_LOW (value));
+	}
+      else
+	/* Otherwise represent the bound as an unsigned value with
+	   the precision of its type.  The precision and signedness
+	   of the type will be necessary to re-interpret it
+	   unambiguously.  */
+	add_AT_wide (die, attr, value);
+      return;
+    }
+
+  /* Otherwise, if it's possible and permitted too, output a reference to
+     another DIE.  */
+  if ((forms & dw_scalar_form_reference) != 0)
+    {
+      tree decl = NULL_TREE;
+
+      /* Some type attributes reference an outer type.  For instance, the upper
+	 bound of an array may reference an embedding record (this happens in
+	 Ada).  */
+      if (TREE_CODE (value) == COMPONENT_REF
+	  && TREE_CODE (TREE_OPERAND (value, 0)) == PLACEHOLDER_EXPR
+	  && TREE_CODE (TREE_OPERAND (value, 1)) == FIELD_DECL)
+	decl = TREE_OPERAND (value, 1);
+
+      else if (TREE_CODE (value) == VAR_DECL
+	       || TREE_CODE (value) == PARM_DECL
+	       || TREE_CODE (value) == RESULT_DECL)
+	decl = value;
+
+      if (decl != NULL_TREE)
+	{
+	  dw_die_ref decl_die = lookup_decl_die (decl);
+
+	  /* ??? Can this happen, or should the variable have been bound
+	     first?  Probably it can, since I imagine that we try to create
+	     the types of parameters in the order in which they exist in
+	     the list, and won't have created a forward reference to a
+	     later parameter.  */
+	  if (decl_die != NULL)
+	    {
+	      add_AT_die_ref (die, attr, decl_die);
+	      return;
+	    }
+	}
+    }
+
+  /* Last chance: try to create a stack operation procedure to evaluate the
+     value.  Do nothing if even that is not possible or permitted.  */
+  if ((forms & dw_scalar_form_exprloc) == 0)
+    return;
+
+  list = loc_list_from_tree (value, 2, context);
+  if (list == NULL || single_element_loc_list_p (list))
+    {
+      /* If this attribute is not a reference nor constant, it is
+	 a DWARF expression rather than location description.  For that
+	 loc_list_from_tree (value, 0, &context) is needed.  */
+      dw_loc_list_ref list2 = loc_list_from_tree (value, 0, context);
+      if (list2 && single_element_loc_list_p (list2))
+	{
+	  add_AT_loc (die, attr, list2->expr);
+	  return;
+	}
+    }
+
+  /* If that failed to give a single element location list, fall back to
+     outputting this as a reference... still if permitted.  */
+  if (list == NULL || (forms & dw_scalar_form_reference) == 0)
+    return;
+
+  if (current_function_decl == 0)
+    ctx = comp_unit_die ();
+  else
+    ctx = lookup_decl_die (current_function_decl);
+
+  decl_die = new_die (DW_TAG_variable, ctx, value);
+  add_AT_flag (decl_die, DW_AT_artificial, 1);
+  add_type_attribute (decl_die, TREE_TYPE (value), TYPE_QUAL_CONST, ctx);
+  add_AT_location_description (decl_die, DW_AT_location, list);
+  add_AT_die_ref (die, attr, decl_die);
+}
+
 /* Return the default for DW_AT_lower_bound, or -1 if there is not any
    default.  */
 
@@ -16517,121 +16722,41 @@  lower_bound_default (void)
    a representation for that bound.  */
 
 static void
-add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr, tree bound)
+add_bound_info (dw_die_ref subrange_die, enum dwarf_attribute bound_attr,
+		tree bound, const struct loc_descr_context *context)
 {
-  switch (TREE_CODE (bound))
-    {
-    case ERROR_MARK:
-      return;
+  int dflt;
 
-    /* All fixed-bounds are represented by INTEGER_CST nodes.  */
-    case INTEGER_CST:
+  while (1)
+    switch (TREE_CODE (bound))
       {
-	unsigned int prec = simple_type_size_in_bits (TREE_TYPE (bound));
-	int dflt;
+      /* Strip all conversions.  */
+      CASE_CONVERT:
+      case VIEW_CONVERT_EXPR:
+	bound = TREE_OPERAND (bound, 0);
+	break;
 
-	/* Use the default if possible.  */
+      /* All fixed-bounds are represented by INTEGER_CST nodes.  Lower bounds
+	 are even omitted when they are the default.  */
+      case INTEGER_CST:
+	/* If the value for this bound is the default one, we can even omit the
+	   attribute.  */
 	if (bound_attr == DW_AT_lower_bound
 	    && tree_fits_shwi_p (bound)
 	    && (dflt = lower_bound_default ()) != -1
 	    && tree_to_shwi (bound) == dflt)
-	  ;
-
-	/* If HOST_WIDE_INT is big enough then represent the bound as
-	   a constant value.  We need to choose a form based on
-	   whether the type is signed or unsigned.  We cannot just
-	   call add_AT_unsigned if the value itself is positive
-	   (add_AT_unsigned might add the unsigned value encoded as
-	   DW_FORM_data[1248]).  Some DWARF consumers will lookup the
-	   bounds type and then sign extend any unsigned values found
-	   for signed types.  This is needed only for
-	   DW_AT_{lower,upper}_bound, since for most other attributes,
-	   consumers will treat DW_FORM_data[1248] as unsigned values,
-	   regardless of the underlying type.  */
-	else if (prec <= HOST_BITS_PER_WIDE_INT
-		 || tree_fits_uhwi_p (bound))
-	  {
-	    if (TYPE_UNSIGNED (TREE_TYPE (bound)))
-	      add_AT_unsigned (subrange_die, bound_attr,
-			       TREE_INT_CST_LOW (bound));
-	    else
-	      add_AT_int (subrange_die, bound_attr, TREE_INT_CST_LOW (bound));
-	  }
-	else
-	  /* Otherwise represent the bound as an unsigned value with
-	     the precision of its type.  The precision and signedness
-	     of the type will be necessary to re-interpret it
-	     unambiguously.  */
-	  add_AT_wide (subrange_die, bound_attr, bound);
-      }
-      break;
-
-    CASE_CONVERT:
-    case VIEW_CONVERT_EXPR:
-      add_bound_info (subrange_die, bound_attr, TREE_OPERAND (bound, 0));
-      break;
-
-    case SAVE_EXPR:
-      break;
-
-    case VAR_DECL:
-    case PARM_DECL:
-    case RESULT_DECL:
-      {
-	dw_die_ref decl_die = lookup_decl_die (bound);
-
-	/* ??? Can this happen, or should the variable have been bound
-	   first?  Probably it can, since I imagine that we try to create
-	   the types of parameters in the order in which they exist in
-	   the list, and won't have created a forward reference to a
-	   later parameter.  */
-	if (decl_die != NULL)
-	  {
-	    add_AT_die_ref (subrange_die, bound_attr, decl_die);
-	    break;
-	  }
-      }
-      /* FALLTHRU */
-
-    default:
-      {
-	/* Otherwise try to create a stack operation procedure to
-	   evaluate the value of the array bound.  */
-
-	dw_die_ref ctx, decl_die;
-	dw_loc_list_ref list;
-
-	list = loc_list_from_tree (bound, 2);
-	if (list == NULL || single_element_loc_list_p (list))
-	  {
-	    /* If DW_AT_*bound is not a reference nor constant, it is
-	       a DWARF expression rather than location description.
-	       For that loc_list_from_tree (bound, 0) is needed.
-	       If that fails to give a single element list,
-	       fall back to outputting this as a reference anyway.  */
-	    dw_loc_list_ref list2 = loc_list_from_tree (bound, 0);
-	    if (list2 && single_element_loc_list_p (list2))
-	      {
-		add_AT_loc (subrange_die, bound_attr, list2->expr);
-		break;
-	      }
-	  }
-	if (list == NULL)
-	  break;
+	  return;
 
-	if (current_function_decl == 0)
-	  ctx = comp_unit_die ();
-	else
-	  ctx = lookup_decl_die (current_function_decl);
+	/* FALLTHRU */
 
-	decl_die = new_die (DW_TAG_variable, ctx, bound);
-	add_AT_flag (decl_die, DW_AT_artificial, 1);
-	add_type_attribute (decl_die, TREE_TYPE (bound), TYPE_QUAL_CONST, ctx);
-	add_AT_location_description (decl_die, DW_AT_location, list);
-	add_AT_die_ref (subrange_die, bound_attr, decl_die);
-	break;
+      default:
+	add_scalar_info (subrange_die, bound_attr, bound,
+			 dw_scalar_form_constant
+			 | dw_scalar_form_exprloc
+			 | dw_scalar_form_reference,
+			 context);
+	return;
       }
-    }
 }
 
 /* Add subscript info to TYPE_DIE, describing an array TYPE, collapsing
@@ -16688,9 +16813,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);
+	  add_bound_info (subrange_die, DW_AT_lower_bound, lower, NULL);
 	  if (upper)
-	    add_bound_info (subrange_die, DW_AT_upper_bound, upper);
+	    add_bound_info (subrange_die, DW_AT_upper_bound, upper, NULL);
 	}
 
       /* Otherwise we have an array type with an unspecified length.  The
@@ -17359,7 +17484,7 @@  gen_array_type_die (tree type, dw_die_ref context_die)
 	       && DECL_P (TYPE_MAX_VALUE (TYPE_DOMAIN (type))))
 	{
 	  tree szdecl = TYPE_MAX_VALUE (TYPE_DOMAIN (type));
-	  dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2);
+	  dw_loc_list_ref loc = loc_list_from_tree (szdecl, 2, NULL);
 
 	  size = int_size_in_bytes (TREE_TYPE (szdecl));
 	  if (loc && size > 0)
@@ -17401,9 +17526,9 @@  gen_array_type_die (tree type, dw_die_ref context_die)
     {
       /* For VECTOR_TYPEs we use an array die with appropriate bounds.  */
       dw_die_ref subrange_die = new_die (DW_TAG_subrange_type, array_die, NULL);
-      add_bound_info (subrange_die, DW_AT_lower_bound, size_zero_node);
+      add_bound_info (subrange_die, DW_AT_lower_bound, size_zero_node, NULL);
       add_bound_info (subrange_die, DW_AT_upper_bound,
-		      size_int (TYPE_VECTOR_SUBPARTS (type) - 1));
+		      size_int (TYPE_VECTOR_SUBPARTS (type) - 1), NULL);
     }
   else
     add_subscript_info (array_die, type, collapse_nested_arrays);
@@ -17429,99 +17554,6 @@  gen_array_type_die (tree type, dw_die_ref context_die)
     add_pubtype (type, array_die);
 }
 
-static dw_loc_descr_ref
-descr_info_loc (tree val, tree base_decl)
-{
-  HOST_WIDE_INT size;
-  dw_loc_descr_ref loc, loc2;
-  enum dwarf_location_atom op;
-
-  if (val == base_decl)
-    return new_loc_descr (DW_OP_push_object_address, 0, 0);
-
-  switch (TREE_CODE (val))
-    {
-    CASE_CONVERT:
-      return descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-    case VAR_DECL:
-      return loc_descriptor_from_tree (val, 0);
-    case INTEGER_CST:
-      if (tree_fits_shwi_p (val))
-	return int_loc_descriptor (tree_to_shwi (val));
-      break;
-    case INDIRECT_REF:
-      size = int_size_in_bytes (TREE_TYPE (val));
-      if (size < 0)
-	break;
-      loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-      if (!loc)
-	break;
-      if (size == DWARF2_ADDR_SIZE)
-	add_loc_descr (&loc, new_loc_descr (DW_OP_deref, 0, 0));
-      else
-	add_loc_descr (&loc, new_loc_descr (DW_OP_deref_size, size, 0));
-      return loc;
-    case POINTER_PLUS_EXPR:
-    case PLUS_EXPR:
-      if (tree_fits_uhwi_p (TREE_OPERAND (val, 1))
-	  && tree_to_uhwi (TREE_OPERAND (val, 1)) < 16384)
-	{
-	  loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-	  if (!loc)
-	    break;
-	  loc_descr_plus_const (&loc, tree_to_shwi (TREE_OPERAND (val, 1)));
-	}
-      else
-	{
-	  op = DW_OP_plus;
-	do_binop:
-	  loc = descr_info_loc (TREE_OPERAND (val, 0), base_decl);
-	  if (!loc)
-	    break;
-	  loc2 = descr_info_loc (TREE_OPERAND (val, 1), base_decl);
-	  if (!loc2)
-	    break;
-	  add_loc_descr (&loc, loc2);
-	  add_loc_descr (&loc2, new_loc_descr (op, 0, 0));
-	}
-      return loc;
-    case MINUS_EXPR:
-      op = DW_OP_minus;
-      goto do_binop;
-    case MULT_EXPR:
-      op = DW_OP_mul;
-      goto do_binop;
-    case EQ_EXPR:
-      op = DW_OP_eq;
-      goto do_binop;
-    case NE_EXPR:
-      op = DW_OP_ne;
-      goto do_binop;
-    default:
-      break;
-    }
-  return NULL;
-}
-
-static void
-add_descr_info_field (dw_die_ref die, enum dwarf_attribute attr,
-		      tree val, tree base_decl)
-{
-  dw_loc_descr_ref loc;
-
-  if (tree_fits_shwi_p (val))
-    {
-      add_AT_unsigned (die, attr, tree_to_shwi (val));
-      return;
-    }
-
-  loc = descr_info_loc (val, base_decl);
-  if (!loc)
-    return;
-
-  add_AT_loc (die, attr, loc);
-}
-
 /* This routine generates DIE for array with hidden descriptor, details
    are filled into *info by a langhook.  */
 
@@ -17531,6 +17563,7 @@  gen_descr_array_type_die (tree type, struct array_descr_info *info,
 {
   const dw_die_ref scope_die = scope_die_for (type, context_die);
   const dw_die_ref array_die = new_die (DW_TAG_array_type, scope_die, type);
+  const struct loc_descr_context context = { type, info->base_decl };
   int dim;
 
   add_name_attribute (array_die, type_tag (type));
@@ -17552,15 +17585,18 @@  gen_descr_array_type_die (tree type, struct array_descr_info *info,
   if (dwarf_version >= 3 || !dwarf_strict)
     {
       if (info->data_location)
-	add_descr_info_field (array_die, DW_AT_data_location,
-			      info->data_location,
-			      info->base_decl);
+	add_scalar_info (array_die, DW_AT_data_location, info->data_location,
+			 dw_scalar_form_exprloc, &context);
       if (info->associated)
-	add_descr_info_field (array_die, DW_AT_associated, info->associated,
-			      info->base_decl);
+	add_scalar_info (array_die, DW_AT_associated, info->associated,
+			 dw_scalar_form_constant
+			 | dw_scalar_form_exprloc
+			 | dw_scalar_form_reference, &context);
       if (info->allocated)
-	add_descr_info_field (array_die, DW_AT_allocated, info->allocated,
-			      info->base_decl);
+	add_scalar_info (array_die, DW_AT_allocated, info->allocated,
+			 dw_scalar_form_constant
+			 | dw_scalar_form_exprloc
+			 | dw_scalar_form_reference, &context);
     }
 
   add_gnat_descriptive_type_attribute (array_die, type, context_die);
@@ -17575,30 +17611,18 @@  gen_descr_array_type_die (tree type, struct array_descr_info *info,
 			    info->dimen[dim].bounds_type, 0,
 			    context_die);
       if (info->dimen[dim].lower_bound)
-	{
-	  /* If it is the default value, omit it.  */
-	  int dflt;
-
-	  if (tree_fits_shwi_p (info->dimen[dim].lower_bound)
-	      && (dflt = lower_bound_default ()) != -1
-	      && tree_to_shwi (info->dimen[dim].lower_bound) == dflt)
-	    ;
-	  else
-	    add_descr_info_field (subrange_die, DW_AT_lower_bound,
-				  info->dimen[dim].lower_bound,
-				  info->base_decl);
-	}
+	add_bound_info (subrange_die, DW_AT_lower_bound,
+			info->dimen[dim].lower_bound, &context);
       if (info->dimen[dim].upper_bound)
-	add_descr_info_field (subrange_die, DW_AT_upper_bound,
-			      info->dimen[dim].upper_bound,
-			      info->base_decl);
-      if (dwarf_version >= 3 || !dwarf_strict)
-	{
-	  if (info->dimen[dim].stride)
-	    add_descr_info_field (subrange_die, DW_AT_byte_stride,
-				  info->dimen[dim].stride,
-				  info->base_decl);
-	}
+	add_bound_info (subrange_die, DW_AT_upper_bound,
+			info->dimen[dim].upper_bound, &context);
+      if ((dwarf_version >= 3 || !dwarf_strict) && info->dimen[dim].stride)
+	add_scalar_info (subrange_die, DW_AT_byte_stride,
+			 info->dimen[dim].stride,
+			 dw_scalar_form_constant
+			 | dw_scalar_form_exprloc
+			 | dw_scalar_form_reference,
+			 &context);
     }
 
   gen_type_die (info->element_type, context_die);
@@ -18662,7 +18686,7 @@  gen_subprogram_die (tree decl, dw_die_ref context_die)
 
       if (fun->static_chain_decl)
 	add_AT_location_description (subr_die, DW_AT_static_link,
-		 loc_list_from_tree (fun->static_chain_decl, 2));
+		 loc_list_from_tree (fun->static_chain_decl, 2, NULL));
     }
 
   /* Generate child dies for template paramaters.  */
@@ -18991,7 +19015,7 @@  gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 	{
 	  if (get_AT (var_die, DW_AT_location) == NULL)
 	    {
-	      loc = loc_list_from_tree (com_decl, off ? 1 : 2);
+	      loc = loc_list_from_tree (com_decl, off ? 1 : 2, NULL);
 	      if (loc)
 		{
 		  if (off)
@@ -19023,7 +19047,7 @@  gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
       com_die_arg.decl_id = DECL_UID (com_decl);
       com_die_arg.die_parent = context_die;
       com_die = common_block_die_table->find (&com_die_arg);
-      loc = loc_list_from_tree (com_decl, 2);
+      loc = loc_list_from_tree (com_decl, 2, NULL);
       if (com_die == NULL)
 	{
 	  const char *cnam
@@ -19037,7 +19061,7 @@  gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
 	      add_AT_location_description (com_die, DW_AT_location, loc);
 	      /* Avoid sharing the same loc descriptor between
 		 DW_TAG_common_block and DW_TAG_variable.  */
-	      loc = loc_list_from_tree (com_decl, 2);
+	      loc = loc_list_from_tree (com_decl, 2, NULL);
 	    }
           else if (DECL_EXTERNAL (decl))
 	    add_AT_flag (com_die, DW_AT_declaration, 1);
@@ -19050,7 +19074,7 @@  gen_variable_die (tree decl, tree origin, dw_die_ref context_die)
       else if (get_AT (com_die, DW_AT_location) == NULL && loc)
 	{
 	  add_AT_location_description (com_die, DW_AT_location, loc);
-	  loc = loc_list_from_tree (com_decl, 2);
+	  loc = loc_list_from_tree (com_decl, 2, NULL);
 	  remove_AT (com_die, DW_AT_declaration);
 	}
       var_die = new_die (DW_TAG_variable, com_die, decl);
-- 
1.7.10.4