OSDN Git Service

* pa.h (OVERRIDE_OPTIONS): Define. Give a warning if -fpic or
[pf3gnuchains/gcc-fork.git] / gcc / dwarfout.c
index 75080a9..49339ae 100644 (file)
@@ -2,7 +2,7 @@
    Network Computing Devices, August, September, October, November 1990.
 
    Output Dwarf format symbol table information from the GNU C compiler.
-   Copyright (C) 1992 Free Software Foundation, Inc.
+   Copyright (C) 1992, 1993 Free Software Foundation, Inc.
 
 This file is part of GNU CC.
 
@@ -28,6 +28,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #include "tree.h"
 #include "flags.h"
 #include "rtl.h"
+#include "hard-reg-set.h"
 #include "insn-config.h"
 #include "reload.h"
 #include "output.h"
@@ -38,7 +39,7 @@ the Free Software Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
 #endif
 
 /* #define NDEBUG 1 */
-#include <assert.h>
+#include "assert.h"
 
 #if defined(DWARF_TIMESTAMPS)
 #if defined(POSIX)
@@ -80,12 +81,11 @@ extern char *rindex ();
 #define ASM_COMMENT_START ";#"
 #endif
 
-/* Define a macro which, when given a pointer to some BLOCK node, returns
-   a pointer to the FUNCTION_DECL node from which the given BLOCK node
-   was instantiated (as an inline expansion).  This macro needs to be
-   defined properly in tree.h, however for the moment, we just fake it.  */
-
-#define BLOCK_INLINE_FUNCTION(block) 0
+/* How to print out a register name.  */
+#ifndef PRINT_REG
+#define PRINT_REG(RTX, CODE, FILE) \
+  fprintf ((FILE), "%s", reg_names[REGNO (RTX)])
+#endif
 
 /* Define a macro which returns non-zero for any tagged type which is
    used (directly or indirectly) in the specification of either some
@@ -284,6 +284,13 @@ static tree fake_containing_scope;
 
 static unsigned current_funcdef_number = 1;
 
+/* A pointer to the ..._DECL node which we have most recently been working
+   on.  We keep this around just in case something about it looks screwy
+   and we want to tell the user what the source coordinates for the actual
+   declaration are.  */
+
+static tree dwarf_last_decl;
+
 /* Forward declarations for functions defined in this file.  */
 
 static void output_type ();
@@ -525,6 +532,12 @@ static unsigned lookup_filename ();
 #ifndef SL_END_LABEL_FMT
 #define SL_END_LABEL_FMT       ".L_sl%u_e"
 #endif
+#ifndef BODY_BEGIN_LABEL_FMT
+#define BODY_BEGIN_LABEL_FMT   ".L_b%u"
+#endif
+#ifndef BODY_END_LABEL_FMT
+#define BODY_END_LABEL_FMT     ".L_b%u_e"
+#endif
 #ifndef FUNC_END_LABEL_FMT
 #define FUNC_END_LABEL_FMT     ".L_f%u_e"
 #endif
@@ -749,6 +762,38 @@ is_pseudo_reg (rtl)
              && (REGNO (XEXP (rtl, 0)) >= FIRST_PSEUDO_REGISTER)));
 }
 
+inline tree
+type_main_variant (type)
+     register tree type;
+{
+  type = TYPE_MAIN_VARIANT (type);
+
+  /* There really should be only one main variant among any group of variants
+     of a given type (and all of the MAIN_VARIANT values for all members of
+     the group should point to that one type) but sometimes the C front-end
+     messes this up for array types, so we work around that bug here.  */
+
+  if (TREE_CODE (type) == ARRAY_TYPE)
+    {
+      while (type != TYPE_MAIN_VARIANT (type))
+        type = TYPE_MAIN_VARIANT (type);
+    }
+
+  return type;
+}
+
+/* Return non-zero if the given type node represents a tagged type.  */
+
+inline int
+is_tagged_type (type)
+     register tree type;
+{
+  register enum tree_code code = TREE_CODE (type);
+
+  return (code == RECORD_TYPE || code == UNION_TYPE
+         || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
+}
+
 static char *
 dwarf_tag_name (tag)
      register unsigned tag;
@@ -870,6 +915,8 @@ dwarf_attr_name (attr)
     case AT_src_info:                  return "AT_src_info";
     case AT_mac_info:                  return "AT_mac_info";
     case AT_src_coords:                        return "AT_src_coords";
+    case AT_body_begin:                        return "AT_body_begin";
+    case AT_body_end:                  return "AT_body_end";
 
     default:                           return "AT_<unknown>";
     }
@@ -977,30 +1024,155 @@ dwarf_fund_type_name (ft)
     case FT_real96:            return "FT_real96";
     case FT_real128:           return "FT_real128";
 
-    default:                   return "<unknown fundamental type>";
+    default:                   return "FT_<unknown>";
+    }
+}
+
+/* Determine the "ultimate origin" of a decl.  The decl may be an
+   inlined instance of an inlined instance of a decl 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
+decl_ultimate_origin (decl)
+     register tree decl;
+{
+  register tree immediate_origin = DECL_ABSTRACT_ORIGIN (decl);
+
+  if (immediate_origin == NULL)
+    return NULL;
+  else
+    {
+      register tree ret_val;
+      register tree lookahead = immediate_origin;
+
+      do
+       {
+         ret_val = lookahead;
+         lookahead = DECL_ABSTRACT_ORIGIN (ret_val);
+       }
+      while (lookahead != NULL && lookahead != ret_val);
+      return ret_val;
+    }
+}
+
+/* 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 (block)
+     register tree block;
+{
+  register tree immediate_origin = BLOCK_ABSTRACT_ORIGIN (block);
+
+  if (immediate_origin == NULL)
+    return NULL;
+  else
+    {
+      register tree ret_val;
+      register 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);
+      return ret_val;
+    }
+}
+
+static void
+output_unsigned_leb128 (value)
+     register unsigned long value;
+{
+  register unsigned long orig_value = value;
+
+  do
+    {
+      register unsigned byte = (value & 0x7f);
+
+      value >>= 7;
+      if (value != 0)  /* more bytes to follow */
+       byte |= 0x80;
+      fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) byte);
+      if (flag_verbose_asm && value == 0)
+       fprintf (asm_out_file, "\t%s ULEB128 number - value = %u",
+                ASM_COMMENT_START, orig_value);
+      fputc ('\n', asm_out_file);
+    }
+  while (value != 0);
+}
+
+static void
+output_signed_leb128 (value)
+     register long value;
+{
+  register long orig_value = value;
+  register int negative = (value < 0);
+  register int more;
+
+  do
+    {
+      register unsigned byte = (value & 0x7f);
+
+      value >>= 7;
+      if (negative)
+       value |= 0xfe000000;  /* manually sign extend */
+      if (((value == 0) && ((byte & 0x40) == 0))
+          || ((value == -1) && ((byte & 0x40) == 1)))
+       more = 0;
+      else
+       {
+         byte |= 0x80;
+         more = 1;
+       }
+      fprintf (asm_out_file, "\t%s\t0x%x", ASM_BYTE_OP, (unsigned) byte);
+      if (flag_verbose_asm && more == 0)
+       fprintf (asm_out_file, "\t%s SLEB128 number - value = %d",
+                ASM_COMMENT_START, orig_value);
+      fputc ('\n', asm_out_file);
     }
+  while (more);
 }
 \f
 /**************** utility functions for attribute functions ******************/
 
 /* Given a pointer to a BLOCK node return non-zero if (and only if) the
-   node in question represents the outermost block (i.e. the "body block")
-   of a function or method.
-
-   For any BLOCK node representing a "body block", the BLOCK_SUPERCONTEXT
-   of the node will point to another BLOCK node which represents the outer-
-   most (function) scope for the function or method.  The BLOCK_SUPERCONTEXT
-   of that node in turn will point to the relevant FUNCTION_DECL node.
+   node in question represents the outermost pair of curly braces (i.e.
+   the "body block") of a function or method.
+
+   For any BLOCK node representing a "body block" of a function or method,
+   the BLOCK_SUPERCONTEXT of the node will point to another BLOCK node
+   which represents the outermost (function) scope for the function or
+   method (i.e. the one which includes the formal parameters).  The
+   BLOCK_SUPERCONTEXT of *that* node in turn will point to the relevant
+   FUNCTION_DECL node.
 */
 
 inline int
 is_body_block (stmt)
      register tree stmt;
 {
-  register enum tree_code code
-    = TREE_CODE (BLOCK_SUPERCONTEXT (BLOCK_SUPERCONTEXT (stmt)));
+  if (TREE_CODE (stmt) == BLOCK)
+    {
+      register tree parent = BLOCK_SUPERCONTEXT (stmt);
+
+      if (TREE_CODE (parent) == BLOCK)
+       {
+         register tree grandparent = BLOCK_SUPERCONTEXT (parent);
 
-  return (code == FUNCTION_DECL);
+         if (TREE_CODE (grandparent) == FUNCTION_DECL)
+           return 1;
+       }
+    }
+  return 0;
 }
 
 /* Given a pointer to a tree node for some type, return a Dwarf fundamental
@@ -1016,9 +1188,9 @@ is_body_block (stmt)
    information about the precise way in which the type was originally
    specified, as in:
 
-       typedef signed int field_type;
+       typedef signed int my_type;
 
-       struct s { field_type f; };
+       struct s { my_type f; };
 
    Since we may be stuck here without enought information to do exactly
    what is called for in the Dwarf draft specification, we do the best
@@ -1165,10 +1337,10 @@ root_type (type)
 
       case POINTER_TYPE:
       case REFERENCE_TYPE:
-       return TYPE_MAIN_VARIANT (root_type (TREE_TYPE (type)));
+       return type_main_variant (root_type (TREE_TYPE (type)));
 
       default:
-       return TYPE_MAIN_VARIANT (type);
+       return type_main_variant (type);
     }
 }
 
@@ -1228,6 +1400,7 @@ type_is_fundamental (type)
       case ARRAY_TYPE:
       case RECORD_TYPE:
       case UNION_TYPE:
+      case QUAL_UNION_TYPE:
       case ENUMERAL_TYPE:
       case FUNCTION_TYPE:
       case METHOD_TYPE:
@@ -1302,13 +1475,35 @@ equate_type_number_to_die_number (type)
      to get the equate to come out right, we need to get the main variant
      itself here.  */
 
-  type = TYPE_MAIN_VARIANT (type);
+  type = type_main_variant (type);
 
   sprintf (type_label, TYPE_NAME_FMT, TYPE_UID (type));
   sprintf (die_label, DIE_BEGIN_LABEL_FMT, current_dienum);
   ASM_OUTPUT_DEF (asm_out_file, type_label, die_label);
 }
 
+static void
+output_reg_number (rtl)
+     register rtx rtl;
+{
+  register unsigned regno = REGNO (rtl);
+
+  if (regno >= FIRST_PSEUDO_REGISTER)
+    {
+      warning_with_decl (dwarf_last_decl, "internal regno botch: regno = %d\n",
+                        regno);
+      regno = 0;
+    }
+  fprintf (asm_out_file, "\t%s\t0x%x",
+          UNALIGNED_INT_ASM_OP, DBX_REGISTER_NUMBER (regno));
+  if (flag_verbose_asm)
+    {
+      fprintf (asm_out_file, "\t%s ", ASM_COMMENT_START);
+      PRINT_REG (rtl, 0, asm_out_file);
+    }
+  fputc ('\n', asm_out_file);
+}
+
 /* The following routine is a nice and simple transducer.  It converts the
    RTL for a variable or parameter (resident in memory) into an equivalent
    Dwarf representation of a mechanism for getting the address of that same
@@ -1345,15 +1540,25 @@ output_mem_loc_descriptor (rtl)
 
        /* Whenever a register number forms a part of the description of
           the method for calculating the (dynamic) address of a memory
-          resident object, Dwarf rules require the register number to
+          resident object, DWARF rules require the register number to
           be referred to as a "base register".  This distinction is not
           based in any way upon what category of register the hardware
           believes the given register belongs to.  This is strictly
-          Dwarf terminology we're dealing with here.  */
+          DWARF terminology we're dealing with here.
+
+          Note that in cases where the location of a memory-resident data
+          object could be expressed as:
+
+                   OP_ADD (OP_BASEREG (basereg), OP_CONST (0))
+
+          the actual DWARF location descriptor that we generate may just
+          be OP_BASEREG (basereg).  This may look deceptively like the
+          object in question was allocated to a register (rather than
+          in memory) so DWARF consumers need to be aware of the subtle
+          distinction between OP_REG and OP_BASEREG.  */
 
        ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_BASEREG);
-        ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
-                               DBX_REGISTER_NUMBER (REGNO (rtl)));
+       output_reg_number (rtl);
        break;
 
       case MEM:
@@ -1408,8 +1613,7 @@ output_loc_descriptor (rtl)
 
     case REG:
        ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_REG);
-        ASM_OUTPUT_DWARF_DATA4 (asm_out_file,
-                               DBX_REGISTER_NUMBER (REGNO (rtl)));
+       output_reg_number (rtl);
        break;
 
     case MEM:
@@ -1527,6 +1731,188 @@ output_enumeral_list (link)
     }
 }
 
+/* Given an unsigned value, round it up to the lowest multiple of `boundary'
+   which is not less than the value itself.  */
+
+inline unsigned
+ceiling (value, boundary)
+     register unsigned value;
+     register unsigned boundary;
+{
+  return (((value + boundary - 1) / boundary) * boundary);
+}
+
+/* Given a pointer to what is assumed to be a FIELD_DECL node, return a
+   pointer to the declared type for the relevant field variable, or return
+   `integer_type_node' if the given node turns out to be an ERROR_MARK node.  */
+
+inline tree
+field_type (decl)
+     register tree decl;
+{
+  register tree type;
+
+  if (TREE_CODE (decl) == ERROR_MARK)
+    return integer_type_node;
+
+  type = DECL_BIT_FIELD_TYPE (decl);
+  if (type == NULL)
+    type = TREE_TYPE (decl);
+  return type;
+}
+
+/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
+   node, return the alignment in bits for the type, or else return
+   BITS_PER_WORD if the node actually turns out to be an ERROR_MARK node.  */
+
+inline unsigned
+simple_type_align_in_bits (type)
+     register tree type;
+{
+  return (TREE_CODE (type) != ERROR_MARK) ? TYPE_ALIGN (type) : BITS_PER_WORD;
+}
+
+/* Given a pointer to a tree node, assumed to be some kind of a ..._TYPE
+   node, return the size in bits for the type if it is a constant, or
+   else return the alignment for the type if the type's size is not
+   constant, or else return BITS_PER_WORD if the type actually turns out
+   to be an ERROR_MARK node.  */
+
+inline unsigned
+simple_type_size_in_bits (type)
+     register tree type;
+{
+  if (TREE_CODE (type) == ERROR_MARK)
+    return BITS_PER_WORD;
+  else
+    {
+      register tree type_size_tree = TYPE_SIZE (type);
+
+      if (TREE_CODE (type_size_tree) != INTEGER_CST)
+       return TYPE_ALIGN (type);
+
+      return (unsigned) TREE_INT_CST_LOW (type_size_tree);
+    }
+}
+
+/* Given a pointer to what is assumed to be a FIELD_DECL node, compute and
+   return the byte offset of the lowest addressed byte of the "containing
+   object" for the given FIELD_DECL, or return 0 if we are unable to deter-
+   mine what that offset is, either because the argument turns out to be a
+   pointer to an ERROR_MARK node, or because the offset is actually variable.
+   (We can't handle the latter case just yet.)  */
+
+static unsigned
+field_byte_offset (decl)
+     register tree decl;
+{
+  register unsigned type_align_in_bytes;
+  register unsigned type_align_in_bits;
+  register unsigned type_size_in_bits;
+  register unsigned object_offset_in_align_units;
+  register unsigned object_offset_in_bits;
+  register unsigned object_offset_in_bytes;
+  register tree type;
+  register tree bitpos_tree;
+  register tree field_size_tree;
+  register unsigned bitpos_int;
+  register unsigned deepest_bitpos;
+  register unsigned field_size_in_bits;
+
+  if (TREE_CODE (decl) == ERROR_MARK)
+    return 0;
+
+  if (TREE_CODE (decl) != FIELD_DECL)
+    abort ();
+
+  type = field_type (decl);
+
+  bitpos_tree = DECL_FIELD_BITPOS (decl);
+  field_size_tree = DECL_SIZE (decl);
+
+  /* We cannot yet cope with fields whose positions or sizes are variable,
+     so for now, when we see such things, we simply return 0.  Someday,
+     we may be able to handle such cases, but it will be damn difficult.  */
+
+  if (TREE_CODE (bitpos_tree) != INTEGER_CST)
+    return 0;
+  bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree);
+
+  if (TREE_CODE (field_size_tree) != INTEGER_CST)
+    return 0;
+  field_size_in_bits = (unsigned) TREE_INT_CST_LOW (field_size_tree);
+
+  type_size_in_bits = simple_type_size_in_bits (type);
+
+  type_align_in_bits = simple_type_align_in_bits (type);
+  type_align_in_bytes = type_align_in_bits / BITS_PER_UNIT;
+
+  /* Note that the GCC front-end doesn't make any attempt to keep track
+     of the starting bit offset (relative to the start of the containing
+     structure type) of the hypothetical "containing object" for a bit-
+     field.  Thus, when computing the byte offset value for the start of
+     the "containing object" of a bit-field, we must deduce this infor-
+     mation on our own.
+
+     This can be rather tricky to do in some cases.  For example, handling
+     the following structure type definition when compiling for an i386/i486
+     target (which only aligns long long's to 32-bit boundaries) can be very
+     tricky:
+
+               struct S {
+                       int             field1;
+                       long long       field2:31;
+               };
+
+     Fortunately, there is a simple rule-of-thumb which can be used in such
+     cases.  When compiling for an i386/i486, GCC will allocate 8 bytes for
+     the structure shown above.  It decides to do this based upon one simple
+     rule for bit-field allocation.  Quite simply, GCC allocates each "con-
+     taining object" for each bit-field at the first (i.e. lowest addressed)
+     legitimate alignment boundary (based upon the required minimum alignment
+     for the declared type of the field) which it can possibly use, subject
+     to the condition that there is still enough available space remaining
+     in the containing object (when allocated at the selected point) to
+     fully accommodate all of the bits of the bit-field itself.
+
+     This simple rule makes it obvious why GCC allocates 8 bytes for each
+     object of the structure type shown above.  When looking for a place to
+     allocate the "containing object" for `field2', the compiler simply tries
+     to allocate a 64-bit "containing object" at each successive 32-bit
+     boundary (starting at zero) until it finds a place to allocate that 64-
+     bit field such that at least 31 contiguous (and previously unallocated)
+     bits remain within that selected 64 bit field.  (As it turns out, for
+     the example above, the compiler finds that it is OK to allocate the
+     "containing object" 64-bit field at bit-offset zero within the
+     structure type.)
+
+     Here we attempt to work backwards from the limited set of facts we're
+     given, and we try to deduce from those facts, where GCC must have
+     believed that the containing object started (within the structure type).
+
+     The value we deduce is then used (by the callers of this routine) to
+     generate AT_location and AT_bit_offset attributes for fields (both
+     bit-fields and, in the case of AT_location, regular fields as well).
+  */
+
+  /* Figure out the bit-distance from the start of the structure to the
+     "deepest" bit of the bit-field.  */
+  deepest_bitpos = bitpos_int + field_size_in_bits;
+
+  /* This is the tricky part.  Use some fancy footwork to deduce where the
+     lowest addressed bit of the containing object must be.  */
+  object_offset_in_bits
+    = ceiling (deepest_bitpos, type_align_in_bits) - type_size_in_bits;
+
+  /* Compute the offset of the containing object in "alignment units".  */
+  object_offset_in_align_units = object_offset_in_bits / type_align_in_bits;
+
+  /* Compute the offset of the containing object in bytes.  */
+  object_offset_in_bytes = object_offset_in_align_units * type_align_in_bytes;
+
+  return object_offset_in_bytes;
+}
+
 /****************************** attributes *********************************/
 
 /* The following routines are responsible for writing out the various types
@@ -1566,71 +1952,61 @@ location_attribute (rtl)
   /* Handle a special case.  If we are about to output a location descriptor
      for a variable or parameter which has been optimized out of existence,
      don't do that.  Instead we output a zero-length location descriptor
-     value as part of the location attribute.  Note that we cannot simply
-     suppress the entire location attribute, because the absence of a
-     location attribute in certain kinds of DIEs is used to indicate some-
-     thing entirely different... i.e. that the DIE represents an object
-     declaration, but not a definition.  So sayeth the PLSIG.  */
+     value as part of the location attribute.
+
+     A variable which has been optimized out of existence will have a
+     DECL_RTL value which denotes a pseudo-reg.
+
+     Currently, in some rare cases, variables can have DECL_RTL values
+     which look like (MEM (REG pseudo-reg#)).  These cases are due to
+     bugs elsewhere in the compiler.  We treat such cases
+     as if the variable(s) in question had been optimized out of existence.
+
+     Note that in all cases where we wish to express the fact that a
+     variable has been optimized out of existence, we do not simply
+     suppress the generation of the entire location attribute because
+     the absence of a location attribute in certain kinds of DIEs is
+     used to indicate something else entirely... i.e. that the DIE
+     represents an object declaration, but not a definition.  So sayeth
+     the PLSIG.
+  */
 
-  if (! is_pseudo_reg (rtl))
+  if (! is_pseudo_reg (rtl)
+      && (GET_CODE (rtl) != MEM || ! is_pseudo_reg (XEXP (rtl, 0))))
     output_loc_descriptor (eliminate_regs (rtl, 0, NULL_RTX));
 
   ASM_OUTPUT_LABEL (asm_out_file, end_label);
 }
 
 /* Output the specialized form of location attribute used for data members
-   of struct types.
+   of struct and union types.
 
    In the special case of a FIELD_DECL node which represents a bit-field,
    the "offset" part of this special location descriptor must indicate the
    distance in bytes from the lowest-addressed byte of the containing
    struct or union type to the lowest-addressed byte of the "containing
-   object" for the bit-field.
+   object" for the bit-field.  (See the `field_byte_offset' function above.)
 
    For any given bit-field, the "containing object" is a hypothetical
    object (of some integral or enum type) within which the given bit-field
    lives.  The type of this hypothetical "containing object" is always the
-   same as the declared type of the individual bit-field itself.
+   same as the declared type of the individual bit-field itself (for GCC
+   anyway... the DWARF spec doesn't actually mandate this).
 
    Note that it is the size (in bytes) of the hypothetical "containing
    object" which will be given in the AT_byte_size attribute for this
-   bit-field.  (See the `byte_size_attribute' function below.)
+   bit-field.  (See the `byte_size_attribute' function below.)  It is
+   also used when calculating the value of the AT_bit_offset attribute.
+   (See the `bit_offset_attribute' function below.)
 */
 
-
 static void
 data_member_location_attribute (decl)
      register tree decl;
 {
+  register unsigned object_offset_in_bytes = field_byte_offset (decl);
   char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
   char end_label[MAX_ARTIFICIAL_LABEL_BYTES];
-  register unsigned type_align_in_bytes;
-  register unsigned type_align_in_bits;
-  register unsigned offset_in_align_units;
-  register unsigned offset_in_bytes;
-  register tree type;
-  register tree bitpos_tree = DECL_FIELD_BITPOS (decl);
-  register unsigned bitpos_int;
-
-  if (TREE_CODE (decl) == ERROR_MARK)
-    return;
-
-  if (TREE_CODE (decl) != FIELD_DECL)
-    abort ();
-
-  /* The bit position given by DECL_FIELD_BITPOS could be non-constant
-     in the case where one or more variable sized members preceded this
-     member in the containing struct type.  We could probably correctly
-     handle this case someday, by it's too complicated to deal with at
-     the moment (and probably too rare to worry about), so just punt on
-     the whole AT_location attribute for now.  Eventually, we'll have
-     to analyze the expression given as the DECL_FIELD_BITPOS and turn
-     it into a member-style AT_location descriptor, but that'll be
-     tough to do.  -- rfg  */
-
-  if (TREE_CODE (bitpos_tree) != INTEGER_CST)
-    return;
-  bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree);
 
   ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_location);
   sprintf (begin_label, LOC_BEGIN_LABEL_FMT, current_dienum);
@@ -1638,105 +2014,7 @@ data_member_location_attribute (decl)
   ASM_OUTPUT_DWARF_DELTA2 (asm_out_file, end_label, begin_label);
   ASM_OUTPUT_LABEL (asm_out_file, begin_label);
   ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_CONST);
-
-  type = DECL_BIT_FIELD_TYPE (decl);
-  if (type == NULL)
-    type = TREE_TYPE (decl);
-
-  type_align_in_bits = TYPE_ALIGN (type);
-  type_align_in_bytes = type_align_in_bits / BITS_PER_UNIT;
-
-  /* WARNING!  Note that the GCC front-end doesn't make any attempt to
-     keep track of the starting bit offset (relative to the start of
-     the containing structure type) of the hypothetical "containing
-     object" for a bit-field.  (See the comments at the start of this
-     function.)  Thus, when computing the byte offset value for a
-     bit-field, all we can do is to divide the starting bit offset of
-     the bit-field by the alignment of the hypothetical "containing
-     object" (which we can easily find) and then multiply by the number
-     of bytes of that alignment.
-
-     This solution only yields an unambiguously correct result when
-     the size of the bit-field is strictly larger than the size of the
-     declared type minus the alignment of the declared type.  When this
-     condition is not satisfied, it means that there is at least an
-     "alignment unit's" worth of other slop which co-resides within the
-     hypothetical "containing object" with the bit field, and this other
-     slop could be either to the left of the bit-field or to the right
-     of the bit-field. (We have no way of knowing which.)
-
-     It also means that we cannot unambiguously tell exactly where the
-     hypothetical "containing object" begins within the containing struct
-     type.  We only know the precise position of the bit-field which is
-     contained therein, and that the hypothetical containing object must
-     be aligned as required for its type.  But when there is at least an
-     alignment unit's worth of slop co-resident in the containing object
-     with the actual bit-field, the actual start of the containing object
-     is ambiguous and thus, we cannot unambiguously determine the "correct"
-     byte offset to put into the AT_location attribute for the bit-field
-     itself.
-
-     This whole thing is a non-issue for the majority of targets, because
-     (for most GCC targets) the alignment of each supported integral type
-     is the same as the size of that type, and thus (size - alignment) for
-     the declared type of any bit-field yields zero, and the size (in bits)
-     of any bit-field must be bigger than zero, so there is never any
-     ambiguity about the starting positions of the containing objects of
-     bit-fields for most GCC targets.
-
-     An exception arises however for some machines (e.g. i386) which have
-     BIGGEST_ALIGNMENT set to something less than the size of type `long
-     long' (i.e. 64) and when we are confronted with something like:
-
-               struct S {
-                       int             field1;
-                       long long       field2:31;
-               };
-
-     Here it is ambiguous (going by DWARF rules anyway) whether the con-
-     taining `long long' object for `field2' should be said to occupy the
-     first and second (32-bit) words of the containing struct type, or
-     whether it should be said to occupy the second and third words of
-     the struct type.
-
-     Currently, GCC allocates 8 bytes (for an i386 target) for each object
-     of the above type.  This is probably a bug however, and GCC should
-     probably be allocating 12 bytes for each such structure (for the i386
-     target).
-
-     Assuming this bug gets fixed, one would have a strong case for saying
-     that the containing `long long' object for `field2' occupies the second
-     and third words of the above structure type, and that `field2' itself
-     occupies the first 31 bits of that containing object.  However consider:
-
-               struct S {
-                       int             field1;
-                       long long       field2:31;
-                       long long       field3:2;
-                       long long       field4:31;
-               };
-
-     Even if the current "member allocation" bug in GCC is fixed, this ex-
-     ample would still illustrate a case in which the starting point of the
-     containing `long long' object for `field4' would be ambiguous, even
-     though we know the exact starting bit offset (within the structure) of
-     the `field4' bit-field itself.
-
-     We essentially just ignore this whole issue here and always act as if
-     most of the slop which co-resides in a containing object along with a
-     bit-field appears in that containing object *AFTER* the bit field.
-     Thus, for the above example, we say that the containing object for
-     `field4' occupies the third and fourth words of the structure type,
-     even though objects of the type only occupy three words.  As long
-     as the debugger understands that the compiler uses this disambiguation
-     rule, the debugger should easily be able to do the Right Thing in all
-     cases.
-  */
-
-  offset_in_align_units = bitpos_int / type_align_in_bits;
-  offset_in_bytes = offset_in_align_units * type_align_in_bytes;
-
-  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, offset_in_bytes);
+  ASM_OUTPUT_DWARF_DATA4 (asm_out_file, object_offset_in_bytes);
   ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_ADD);
   ASM_OUTPUT_LABEL (asm_out_file, end_label);
 }
@@ -1812,6 +2090,9 @@ const_value_attribute (rtl)
           we just punt and generate an AT_const_value attribute with form
           FORM_BLOCK4 and a length of zero.  */
        break;
+
+      default:
+       abort ();  /* No other kinds of rtx should be possible here.  */
     }
 
   ASM_OUTPUT_LABEL (asm_out_file, end_label);
@@ -1839,68 +2120,109 @@ location_or_const_value_attribute (decl)
     return;
 
   if ((TREE_CODE (decl) != VAR_DECL) && (TREE_CODE (decl) != PARM_DECL))
-    abort ();
+    {
+      /* Should never happen.  */
+      abort ();
+      return;
+    }
 
-  /* Existing Dwarf debuggers need and expect the location descriptors for
-     formal parameters to reflect either the place where the parameters get
-     passed (if they are passed on the stack and in memory) or else the
-     (preserved) registers which the parameters get copied to during the
-     function prologue.
-
-     At least this is the way things are for most common CISC machines
-     (e.g. x86 and m68k) where parameters are passed in the stack, and for
-     most common RISC machines (e.g. i860 and m88k) where parameters are
-     passed in registers.
-
-     The rules for Sparc are a little weird for some reason.  The DWARF
-     generated by the USL C compiler for the Sparc/svr4 reference port says
-     that the parameters are passed in the stack.  I haven't figured out
-     how to duplicate that behavior here (for the Sparc) yet, or even if
-     I really need to.
-
-     Note that none of this is clearly spelled out in the current Dwarf
-     version 1 specification, but it's obvious if you look at the output of
-     the CI5 compiler, or if you try to use the svr4 SDB debugger.  Hopefully,
-     a later version of the Dwarf specification will clarify this.  For now,
-     we just need to generate the right thing.  Note that Dwarf version 2
-     will provide us with a means to describe *all* of the locations in which
-     a given variable or parameter resides (and the PC ranges over which it
-     occupies each one), but for now we can only describe one "location"
-     for each formal parameter passed, and so we just try to mimic existing
-     practice as much as possible.
+  /* Here we have to decide where we are going to say the parameter "lives"
+     (as far as the debugger is concerned).  We only have a couple of choices.
+     GCC provides us with DECL_RTL and with DECL_INCOMING_RTL.  DECL_RTL
+     normally indicates where the parameter lives during most of the activa-
+     tion of the function.  If optimization is enabled however, this could
+     be either NULL or else a pseudo-reg.  Both of those cases indicate that
+     the parameter doesn't really live anywhere (as far as the code generation
+     parts of GCC are concerned) during most of the function's activation.
+     That will happen (for example) if the parameter is never referenced
+     within the function.
+
+     We could just generate a location descriptor here for all non-NULL
+     non-pseudo values of DECL_RTL and ignore all of the rest, but we can
+     be a little nicer than that if we also consider DECL_INCOMING_RTL in
+     cases where DECL_RTL is NULL or is a pseudo-reg.
+
+     Note however that we can only get away with using DECL_INCOMING_RTL as
+     a backup substitute for DECL_RTL in certain limited cases.  In cases
+     where DECL_ARG_TYPE(decl) indicates the same type as TREE_TYPE(decl)
+     we can be sure that the parameter was passed using the same type as it
+     is declared to have within the function, and that its DECL_INCOMING_RTL
+     points us to a place where a value of that type is passed.  In cases
+     where DECL_ARG_TYPE(decl) and TREE_TYPE(decl) are different types
+     however, we cannot (in general) use DECL_INCOMING_RTL as a backup
+     substitute for DECL_RTL because in these cases, DECL_INCOMING_RTL
+     points us to a value of some type which is *different* from the type
+     of the parameter itself.  Thus, if we tried to use DECL_INCOMING_RTL
+     to generate a location attribute in such cases, the debugger would
+     end up (for example) trying to fetch a `float' from a place which
+     actually contains the first part of a `double'.  That would lead to
+     really incorrect and confusing output at debug-time, and we don't
+     want that now do we?
+
+     So in general, we DO NOT use DECL_INCOMING_RTL as a backup for DECL_RTL
+     in cases where DECL_ARG_TYPE(decl) != TREE_TYPE(decl).  There are a
+     couple of cute exceptions however.  On little-endian machines we can
+     get away with using DECL_INCOMING_RTL even when DECL_ARG_TYPE(decl) is
+     not the same as TREE_TYPE(decl) but only when DECL_ARG_TYPE(decl) is
+     an integral type which is smaller than TREE_TYPE(decl).  These cases
+     arise when (on a little-endian machine) a non-prototyped function has
+     a parameter declared to be of type `short' or `char'.  In such cases,
+     TREE_TYPE(decl) will be `short' or `char', DECL_ARG_TYPE(decl) will be
+     `int', and DECL_INCOMING_RTL will point to the lowest-order byte of the
+     passed `int' value.  If the debugger then uses that address to fetch a
+     `short' or a `char' (on a little-endian machine) the result will be the
+     correct data, so we allow for such exceptional cases below.
+
+     Note that our goal here is to describe the place where the given formal
+     parameter lives during most of the function's activation (i.e. between
+     the end of the prologue and the start of the epilogue).  We'll do that
+     as best as we can.  Note however that if the given formal parameter is
+     modified sometime during the execution of the function, then a stack
+     backtrace (at debug-time) will show the function as having been called
+     with the *new* value rather than the value which was originally passed
+     in.  This happens rarely enough that it is not a major problem, but it
+     *is* a problem, and I'd like to fix it.  A future version of dwarfout.c
+     may generate two additional attributes for any given TAG_formal_parameter
+     DIE which will describe the "passed type" and the "passed location" for
+     the given formal parameter in addition to the attributes we now generate
+     to indicate the "declared type" and the "active location" for each
+     parameter.  This additional set of attributes could be used by debuggers
+     for stack backtraces.
+
+     Separately, note that sometimes DECL_RTL can be NULL and DECL_INCOMING_RTL
+     can be NULL also.  This happens (for example) for inlined-instances of
+     inline function formal parameters which are never referenced.  This really
+     shouldn't be happening.  All PARM_DECL nodes should get valid non-NULL
+     DECL_INCOMING_RTL values, but integrate.c doesn't currently generate
+     these values for inlined instances of inline function parameters, so
+     when we see such cases, we are just SOL (shit-out-of-luck) for the time
+     being (until integrate.c gets fixed).
   */
 
-  if (TREE_CODE (decl) != PARM_DECL)
-    /*  If this decl is not a formal parameter, just use DECL_RTL.  */
-    rtl = DECL_RTL (decl);
-  else
-    {
-      if (GET_CODE (DECL_INCOMING_RTL (decl)) == MEM)
-        /* Parameter was passed in memory, so say that's where it lives.  */
-       rtl = DECL_INCOMING_RTL (decl);
-      else
-       {
-          /* Parameter was passed in a register, so say it lives in the
-            register it will be copied to during the prologue.  */
-          rtl = DECL_RTL (decl);
-
-         /* Note that in cases where the formal parameter is never used
-            and where this compilation is done with -O, the copying of
-            of an incoming register parameter to another register (in
-            the prologue) can be totally optimized away.  (In such cases
-            the DECL_RTL will indicate a pseudo-register.)  We could just
-            use the DECL_RTL (as we normally do for register parameters)
-            in these cases, but if we did that, we would end up generating
-            a null location descriptor.  (See `location_attribute' above.)
-            That would be acceptable (according to the DWARF spec) but it
-            is probably more useful to say that the formal resides where
-            it was passed instead of saying that it resides nowhere.  */
-         if (is_pseudo_reg (rtl))
-           rtl = DECL_INCOMING_RTL (decl);
-       }
-    }
+  /* Use DECL_RTL as the "location" unless we find something better.  */
+  rtl = DECL_RTL (decl);
+
+  if (TREE_CODE (decl) == PARM_DECL)
+    if (rtl == NULL_RTX || is_pseudo_reg (rtl))
+      {
+       /* This decl represents a formal parameter which was optimized out.  */
+        register tree declared_type = type_main_variant (TREE_TYPE (decl));
+        register tree passed_type = type_main_variant (DECL_ARG_TYPE (decl));
+
+       /* Note that DECL_INCOMING_RTL may be NULL in here, but we handle
+          *all* cases where (rtl == NULL_RTX) just below.  */
+
+       if (declared_type == passed_type)
+         rtl = DECL_INCOMING_RTL (decl);
+#if (BYTES_BIG_ENDIAN == 0)
+       else
+         if (TREE_CODE (declared_type) == INTEGER_TYPE)
+           if (TYPE_SIZE (declared_type) <= TYPE_SIZE (passed_type))
+             rtl = DECL_INCOMING_RTL (decl);
+#endif /* (BYTES_BIG_ENDIAN == 0) */
+      }
 
-  if (rtl == NULL)
+  if (rtl == NULL_RTX)
     return;
 
   switch (GET_CODE (rtl))
@@ -2000,6 +2322,7 @@ mod_u_d_type_attribute (type, decl_const, decl_volatile)
   ASM_OUTPUT_LABEL (asm_out_file, end_label);
 }
 
+#ifdef USE_ORDERING_ATTRIBUTE
 inline void
 ordering_attribute (ordering)
      register unsigned ordering;
@@ -2007,6 +2330,7 @@ ordering_attribute (ordering)
   ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_ordering);
   ASM_OUTPUT_DWARF_DATA2 (asm_out_file, ordering);
 }
+#endif /* defined(USE_ORDERING_ATTRIBUTE) */
 
 /* Note that the block of subscript information for an array type also
    includes information about the element type of type given array type.  */
@@ -2129,17 +2453,17 @@ byte_size_attribute (tree_node)
       case ENUMERAL_TYPE:
       case RECORD_TYPE:
       case UNION_TYPE:
+      case QUAL_UNION_TYPE:
        size = int_size_in_bytes (tree_node);
        break;
 
       case FIELD_DECL:
        /* For a data member of a struct or union, the AT_byte_size is
-          always given as the number of bytes normally allocated for
+          generally given as the number of bytes normally allocated for
           an object of the *declared* type of the member itself.  This
           is true even for bit-fields.  */
-       size = int_size_in_bytes (DECL_BIT_FIELD_TYPE (tree_node)
-                                 ? DECL_BIT_FIELD_TYPE (tree_node)
-                                 : TREE_TYPE (tree_node));
+       size = simple_type_size_in_bits (field_type (tree_node))
+              / BITS_PER_UNIT;
        break;
 
       default:
@@ -2164,6 +2488,10 @@ byte_size_attribute (tree_node)
    lives.  The type of this hypothetical "containing object" is always the
    same as the declared type of the individual bit-field itself.
 
+   The determination of the exact location of the "containing object" for
+   a bit-field is rather complicated.  It's handled by the `field_byte_offset'
+   function (above).
+
    Note that it is the size (in bytes) of the hypothetical "containing
    object" which will be given in the AT_byte_size attribute for this
    bit-field.  (See `byte_size_attribute' above.)
@@ -2173,51 +2501,50 @@ inline void
 bit_offset_attribute (decl)
     register tree decl;
 {
+  register unsigned object_offset_in_bytes = field_byte_offset (decl);
   register tree type = DECL_BIT_FIELD_TYPE (decl);
-  register unsigned dwarf_bit_offset;
   register tree bitpos_tree = DECL_FIELD_BITPOS (decl);
   register unsigned bitpos_int;
+  register unsigned highest_order_object_bit_offset;
+  register unsigned highest_order_field_bit_offset;
+  register unsigned bit_offset;
 
   assert (TREE_CODE (decl) == FIELD_DECL);     /* Must be a field.  */
   assert (type);                               /* Must be a bit field.  */
 
-  /* The bit position given by DECL_FIELD_BITPOS could be non-constant
-     in the case where one or more variable sized members preceded this
-     member in the containing struct type.  We could probably correctly
-     handle this case someday, by it's too complicated to deal with at
-     the moment, so just punt on the whole AT_bit_offset attribute for
-     now.  Eventually, we'll have to analyze the (variable) expression
-     given as the DECL_FIELD_BITPOS and see if we can factor out just
-     the (constant) bit offset part of that expression.  -- rfg  */
+  /* We can't yet handle bit-fields whose offsets are variable, so if we
+     encounter such things, just return without generating any attribute
+     whatsoever.  */
 
   if (TREE_CODE (bitpos_tree) != INTEGER_CST)
     return;
   bitpos_int = (unsigned) TREE_INT_CST_LOW (bitpos_tree);
 
-  /* For a detailed description of how the AT_bit_offset attribute value
-     is calculated, see the comments in `data_member_location_attribute'
-     above.  */
+  /* Note that the bit offset is always the distance (in bits) from the
+     highest-order bit of the "containing object" to the highest-order
+     bit of the bit-field itself.  Since the "high-order end" of any
+     object or field is different on big-endian and little-endian machines,
+     the computation below must take account of these differences.  */
 
-#if (BYTES_BIG_ENDIAN == 1)
-  dwarf_bit_offset = bitpos_int % TYPE_ALIGN (type);
-#else
-  {
-    register unsigned high_order_bitpos
-      = bitpos_int + (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl));
-    register tree type_size_tree = TYPE_SIZE (type);
-    register unsigned type_size_in_bits;
+  highest_order_object_bit_offset = object_offset_in_bytes * BITS_PER_UNIT;
+  highest_order_field_bit_offset = bitpos_int;
 
-    if (TREE_CODE (type_size_tree) != INTEGER_CST)
-      abort ();
-    type_size_in_bits = (unsigned) TREE_INT_CST_LOW (type_size_tree);
+#if (BYTES_BIG_ENDIAN == 0)
+  highest_order_field_bit_offset
+    += (unsigned) TREE_INT_CST_LOW (DECL_SIZE (decl));
 
-    dwarf_bit_offset = type_size_in_bits
-                       - (high_order_bitpos % TYPE_ALIGN (type));
-  }
-#endif
+  highest_order_object_bit_offset += simple_type_size_in_bits (type);
+#endif /* (BYTES_BIG_ENDIAN == 0) */
+
+  bit_offset =
+#if (BYTES_BIG_ENDIAN == 0)
+         highest_order_object_bit_offset - highest_order_field_bit_offset;
+#else /* (BYTES_BIG_ENDIAN != 0) */
+         highest_order_field_bit_offset - highest_order_object_bit_offset;
+#endif /* (BYTES_BIG_ENDIAN != 0) */
 
   ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_bit_offset);
-  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, dwarf_bit_offset);
+  ASM_OUTPUT_DWARF_DATA2 (asm_out_file, bit_offset);
 }
 
 /* For a FIELD_DECL node which represents a bit field, output an attribute
@@ -2297,6 +2624,26 @@ high_pc_attribute (asm_high_label)
   ASM_OUTPUT_DWARF_ADDR (asm_out_file, asm_high_label);
 }
 
+/* Generate an AT_body_begin attribute for a subroutine DIE.  */
+
+inline void
+body_begin_attribute (asm_begin_label)
+     register char *asm_begin_label;
+{
+  ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_body_begin);
+  ASM_OUTPUT_DWARF_ADDR (asm_out_file, asm_begin_label);
+}
+
+/* Generate an AT_body_end attribute for a subroutine DIE.  */
+
+inline void
+body_end_attribute (asm_end_label)
+     register char *asm_end_label;
+{
+  ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_body_end);
+  ASM_OUTPUT_DWARF_ADDR (asm_out_file, asm_end_label);
+}
+
 /* Generate an AT_language attribute given a LANG value.  These attributes
    are used only within TAG_compile_unit DIEs.  */
 
@@ -2316,9 +2663,7 @@ member_attribute (context)
 
   /* Generate this attribute only for members in C++.  */
 
-  if (context != NULL
-      && (TREE_CODE (context) == RECORD_TYPE
-         || TREE_CODE (context) == UNION_TYPE))
+  if (context != NULL && is_tagged_type (context))
     {
       ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_member);
       sprintf (label, TYPE_NAME_FMT, TYPE_UID (context));
@@ -2401,7 +2746,7 @@ inline void
 inline_attribute (decl)
      register tree decl;
 {
-  if (TREE_INLINE (decl))
+  if (DECL_INLINE (decl))
     {
       ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_inline);
       ASM_OUTPUT_DWARF_STRING (asm_out_file, "");
@@ -2461,9 +2806,11 @@ pure_or_virtual_attribute (func_decl)
 {
   if (DECL_VIRTUAL_P (func_decl))
     {
+#if 0 /* DECL_ABSTRACT_VIRTUAL_P is C++-specific.  */
       if (DECL_ABSTRACT_VIRTUAL_P (func_decl))
         ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_pure_virtual);
       else
+#endif
         ASM_OUTPUT_DWARF_ATTRIBUTE (asm_out_file, AT_virtual);
       ASM_OUTPUT_DWARF_STRING (asm_out_file, "");
     }
@@ -2476,7 +2823,7 @@ pure_or_virtual_attribute (func_decl)
 /* Output an AT_name attribute and an AT_src_coords attribute for the
    given decl, but only if it actually has a name.  */
 
-inline void
+static void
 name_and_src_coords_attributes (decl)
     register tree decl;
 {
@@ -2505,7 +2852,7 @@ name_and_src_coords_attributes (decl)
 
         src_coords_attribute (file_index, DECL_SOURCE_LINE (decl));
       }
-#endif
+#endif /* defined(DWARF_DECL_COORDINATES) */
     }
 }
 
@@ -2544,7 +2891,16 @@ type_attribute (type, decl_const, decl_volatile)
     if (root_type_modified)
        mod_u_d_type_attribute (type, decl_const, decl_volatile);
     else
-       user_def_type_attribute (type);
+       /* We have to get the type_main_variant here (and pass that to the
+          `user_def_type_attribute' routine) because the ..._TYPE node we
+          have might simply be a *copy* of some original type node (where
+          the copy was created to help us keep track of typedef names)
+          and that copy might have a different TYPE_UID from the original
+          ..._TYPE node.  (Note that when `equate_type_number_to_die_number'
+          is labeling a given type DIE for future reference, it always and
+          only creates labels for DIEs representing *main variants*, and it
+          never even knows about non-main-variants.)  */
+       user_def_type_attribute (type_main_variant (type));
 }
 
 /* Given a tree pointer to a struct, class, union, or enum type node, return
@@ -2653,9 +3009,9 @@ output_array_type_die (arg)
      we will only do so for multidimensional arrays.  After all, we don't
      want to waste space in the .debug section now do we?)  */
 
-#if 0
+#ifdef USE_ORDERING_ATTRIBUTE
   ordering_attribute (ORD_row_major);
-#endif
+#endif /* defined(USE_ORDERING_ATTRIBUTE) */
 
   subscript_data_attribute (type);
 }
@@ -2680,17 +3036,67 @@ output_entry_point_die (arg)
      register void *arg;
 {
   register tree decl = arg;
-  register tree type = TREE_TYPE (decl);
-  register tree return_type = TREE_TYPE (type);
+  register tree origin = decl_ultimate_origin (decl);
 
   ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_entry_point);
   sibling_attribute ();
   dienum_push ();
-  name_and_src_coords_attributes (decl);
-  member_attribute (DECL_CONTEXT (decl));
-  type_attribute (return_type, 0, 0);
-}
-#endif
+  if (origin != NULL)
+    abstract_origin_attribute (origin);
+  else
+    {
+      name_and_src_coords_attributes (decl);
+      member_attribute (DECL_CONTEXT (decl));
+      type_attribute (TREE_TYPE (TREE_TYPE (decl)), 0, 0);
+    }
+  if (DECL_ABSTRACT (decl))
+    equate_decl_number_to_die_number (decl);
+  else
+    low_pc_attribute (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+}
+#endif
+
+/* Output a DIE to represent an inlined instance of an enumeration type.  */
+
+static void
+output_inlined_enumeration_type_die (arg)
+     register void *arg;
+{
+  register tree type = arg;
+
+  ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_enumeration_type);
+  sibling_attribute ();
+  assert (TREE_ASM_WRITTEN (type));
+  abstract_origin_attribute (type);
+}
+
+/* Output a DIE to represent an inlined instance of a structure type.  */
+
+static void
+output_inlined_structure_type_die (arg)
+     register void *arg;
+{
+  register tree type = arg;
+
+  ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_structure_type);
+  sibling_attribute ();
+  assert (TREE_ASM_WRITTEN (type));
+  abstract_origin_attribute (type);
+}
+
+/* Output a DIE to represent an inlined instance of a union type.  */
+
+static void
+output_inlined_union_type_die (arg)
+     register void *arg;
+{
+  register tree type = arg;
+
+  ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_union_type);
+  sibling_attribute ();
+  assert (TREE_ASM_WRITTEN (type));
+  abstract_origin_attribute (type);
+}
 
 /* Output a DIE to represent an enumeration type.  Note that these DIEs
    include all of the information about the enumeration values also.
@@ -2724,37 +3130,51 @@ output_enumeration_type_die (arg)
    function type.
 
    Note that this routine is a bit unusual because its argument may be
-   either a PARM_DECL node or else some sort of a ..._TYPE node.  If it's
-   the formar then this function is being called to output a real live
-   formal parameter declaration.  If it's the latter, then this function
-   is only being called to output a TAG_formal_parameter DIE to stand as
-   a placeholder for some formal argument type of some subprogram type.  */
+   a ..._DECL node (i.e. either a PARM_DECL or perhaps a VAR_DECL which
+   represents an inlining of some PARM_DECL) or else some sort of a
+   ..._TYPE node.  If it's the former then this function is being called
+   to output a DIE to represent a formal parameter object (or some inlining
+   thereof).  If it's the latter, then this function is only being called
+   to output a TAG_formal_parameter DIE to stand as a placeholder for some
+   formal argument type of some subprogram type.  */
 
 static void
 output_formal_parameter_die (arg)
      register void *arg;
 {
-  register tree decl = arg;
-  register tree type;
-
-  if (TREE_CODE (decl) == PARM_DECL)
-    type = TREE_TYPE (decl);
-  else
-    {
-      type = decl;     /* we were called with a type, not a decl */
-      decl = NULL;
-    }
+  register tree node = arg;
 
   ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_formal_parameter);
   sibling_attribute ();
-  if (decl)
+
+  switch (TREE_CODE_CLASS (TREE_CODE (node)))
     {
-      name_and_src_coords_attributes (decl);
-      type_attribute (type, TREE_READONLY (decl), TREE_THIS_VOLATILE (decl));
-      location_or_const_value_attribute (decl);
+    case 'd':  /* We were called with some kind of a ..._DECL node.  */
+      {
+       register tree origin = decl_ultimate_origin (node);
+
+       if (origin != NULL)
+         abstract_origin_attribute (origin);
+       else
+         {
+           name_and_src_coords_attributes (node);
+           type_attribute (TREE_TYPE (node),
+                           TREE_READONLY (node), TREE_THIS_VOLATILE (node));
+         }
+       if (DECL_ABSTRACT (node))
+         equate_decl_number_to_die_number (node);
+       else
+         location_or_const_value_attribute (node);
+      }
+      break;
+
+    case 't':  /* We were called with some kind of a ..._TYPE node.  */
+      type_attribute (node, 0, 0);
+      break;
+
+    default:
+      abort ();        /* Should never happen.  */
     }
-  else
-    type_attribute (type, 0, 0);
 }
 
 /* Output a DIE to represent a declared function (either file-scope
@@ -2765,24 +3185,40 @@ output_global_subroutine_die (arg)
      register void *arg;
 {
   register tree decl = arg;
-  register tree type = TREE_TYPE (decl);
-  register tree return_type = TREE_TYPE (type);
+  register tree origin = decl_ultimate_origin (decl);
 
   ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_global_subroutine);
   sibling_attribute ();
   dienum_push ();
-  name_and_src_coords_attributes (decl);
-  inline_attribute (decl);
-  prototyped_attribute (type);
-  member_attribute (DECL_CONTEXT (decl));
-  type_attribute (return_type, 0, 0);
-  if (!TREE_EXTERNAL (decl))
+  if (origin != NULL)
+    abstract_origin_attribute (origin);
+  else
     {
-      char func_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+      register tree type = TREE_TYPE (decl);
 
-      low_pc_attribute (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
-      sprintf (func_end_label, FUNC_END_LABEL_FMT, current_funcdef_number);
-      high_pc_attribute (func_end_label);
+      name_and_src_coords_attributes (decl);
+      inline_attribute (decl);
+      prototyped_attribute (type);
+      member_attribute (DECL_CONTEXT (decl));
+      type_attribute (TREE_TYPE (type), 0, 0);
+      pure_or_virtual_attribute (decl);
+    }
+  if (DECL_ABSTRACT (decl))
+    equate_decl_number_to_die_number (decl);
+  else
+    {
+      if (! DECL_EXTERNAL (decl))
+       {
+         char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+         low_pc_attribute (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+         sprintf (label, FUNC_END_LABEL_FMT, current_funcdef_number);
+         high_pc_attribute (label);
+         sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
+         body_begin_attribute (label);
+         sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
+         body_end_attribute (label);
+       }
     }
 }
 
@@ -2794,103 +3230,64 @@ output_global_variable_die (arg)
      register void *arg;
 {
   register tree decl = arg;
-  register tree type = TREE_TYPE (decl);
+  register tree origin = decl_ultimate_origin (decl);
 
   ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_global_variable);
   sibling_attribute ();
-  name_and_src_coords_attributes (decl);
-  member_attribute (DECL_CONTEXT (decl));
-  type_attribute (type, TREE_READONLY (decl), TREE_THIS_VOLATILE (decl));
-  if (!TREE_EXTERNAL (decl))
-    location_or_const_value_attribute (decl);
-}
-
-#if 0
-/* TAG_inline_subroutine has been retired by the UI/PLSIG.  We're
-   now supposed to use either TAG_subroutine or TAG_global_subroutine
-   (depending on whether or not the function in question has internal
-   or external linkage) and we're supposed to just put in an AT_inline
-   attribute.  */
-static void
-output_inline_subroutine_die (arg)
-     register void *arg;
-{
-  register tree decl = arg;
-  register tree type = TREE_TYPE (decl);
-  register tree return_type = TREE_TYPE (type);
-
-  ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_inline_subroutine);
-  sibling_attribute ();
-  dienum_push ();
-  name_and_src_coords_attributes (decl);
-  prototyped_attribute (type);
-  member_attribute (DECL_CONTEXT (decl));
-  type_attribute (return_type, 0, 0);
-
-  /* Note:  For each inline function which gets an out-of-line body
-     generated for it, we want to generate AT_low_pc and AT_high_pc
-     attributes here for the function's out-of-line body.
-
-     Unfortunately, the decision as to whether or not to generate an
-     out-of-line body for any given inline function may not be made
-     until we reach the end of the containing scope for the given
-     inline function (because only then will it be known if the
-     function was ever even called).
-
-     For this reason, the output of DIEs representing file-scope inline
-     functions gets delayed until a special post-pass which happens only
-     after we have reached the end of the compilation unit.  Because of
-     this mechanism, we can always be sure (by the time we reach here)
-     that TREE_ASM_WRITTEN(decl) will correctly indicate whether or not
-     there was an out-of-line body generated for this inline function.
-  */
-
-  if (!TREE_EXTERNAL (decl))
+  if (origin != NULL)
+    abstract_origin_attribute (origin);
+  else
     {
-      if (TREE_ASM_WRITTEN (decl))
-        {
-          char func_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
-
-          low_pc_attribute (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
-          sprintf (func_end_label, FUNC_END_LABEL_FMT, current_funcdef_number);
-          high_pc_attribute (func_end_label);
-        }
+      name_and_src_coords_attributes (decl);
+      member_attribute (DECL_CONTEXT (decl));
+      type_attribute (TREE_TYPE (decl),
+                     TREE_READONLY (decl), TREE_THIS_VOLATILE (decl));
+    }
+  if (DECL_ABSTRACT (decl))
+    equate_decl_number_to_die_number (decl);
+  else
+    {
+      if (!DECL_EXTERNAL (decl))
+       location_or_const_value_attribute (decl);
     }
 }
-#endif
 
 static void
 output_label_die (arg)
      register void *arg;
 {
   register tree decl = arg;
-  register rtx insn = DECL_RTL (decl);
+  register tree origin = decl_ultimate_origin (decl);
 
   ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_label);
   sibling_attribute ();
-  name_and_src_coords_attributes (decl);
-
-  /* When optimization is enabled (with -O) the code in jump.c and in flow.c
-     may cause insns representing one of more of the user's own labels to
-     be deleted.  This happens whenever it is determined that a given label
-     is unreachable.
+  if (origin != NULL)
+    abstract_origin_attribute (origin);
+  else
+    name_and_src_coords_attributes (decl);
+  if (DECL_ABSTRACT (decl))
+    equate_decl_number_to_die_number (decl);
+  else
+    {
+      register rtx insn = DECL_RTL (decl);
 
-     In such cases, we here generate an abbreviated form of a label DIE.
-     This abbreviated version does *not* have a low_pc attribute.  This
-     should signify to the debugger that the label has been optimized away.
+      if (GET_CODE (insn) == CODE_LABEL)
+       {
+         char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
-     Note that a CODE_LABEL can get deleted either by begin converted into
-     a NOTE_INSN_DELETED note, or by simply having its INSN_DELETED_P flag
-     set to true.  We handle both cases here.
-  */
+         /* When optimization is enabled (via -O) some parts of the compiler
+            (e.g. jump.c and cse.c) may try to delete CODE_LABEL insns which
+            represent source-level labels which were explicitly declared by
+            the user.  This really shouldn't be happening though, so catch
+            it if it ever does happen.  */
 
-  if (GET_CODE (insn) == CODE_LABEL && ! INSN_DELETED_P (insn))
-    {
-      char label[MAX_ARTIFICIAL_LABEL_BYTES];
+         if (INSN_DELETED_P (insn))
+           abort ();   /* Should never happen.  */
 
-      sprintf (label, INSN_LABEL_FMT, current_funcdef_number,
-                                     (unsigned) INSN_UID (insn));
-      low_pc_attribute (label);
+         sprintf (label, INSN_LABEL_FMT, current_funcdef_number,
+                                         (unsigned) INSN_UID (insn));
+         low_pc_attribute (label);
+       }
     }
 }
 
@@ -2899,16 +3296,20 @@ output_lexical_block_die (arg)
      register void *arg;
 {
   register tree stmt = arg;
-  char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
-  char end_label[MAX_ARTIFICIAL_LABEL_BYTES];
 
   ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_lexical_block);
   sibling_attribute ();
   dienum_push ();
-  sprintf (begin_label, BLOCK_BEGIN_LABEL_FMT, next_block_number);
-  low_pc_attribute (begin_label);
-  sprintf (end_label, BLOCK_END_LABEL_FMT, next_block_number);
-  high_pc_attribute (end_label);
+  if (! BLOCK_ABSTRACT (stmt))
+    {
+      char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
+      char end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+      sprintf (begin_label, BLOCK_BEGIN_LABEL_FMT, next_block_number);
+      low_pc_attribute (begin_label);
+      sprintf (end_label, BLOCK_END_LABEL_FMT, next_block_number);
+      high_pc_attribute (end_label);
+    }
 }
 
 static void
@@ -2916,16 +3317,21 @@ output_inlined_subroutine_die (arg)
      register void *arg;
 {
   register tree stmt = arg;
-  char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
-  char end_label[MAX_ARTIFICIAL_LABEL_BYTES];
 
   ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_inlined_subroutine);
   sibling_attribute ();
   dienum_push ();
-  sprintf (begin_label, BLOCK_BEGIN_LABEL_FMT, next_block_number);
-  low_pc_attribute (begin_label);
-  sprintf (end_label, BLOCK_END_LABEL_FMT, next_block_number);
-  high_pc_attribute (end_label);
+  abstract_origin_attribute (block_ultimate_origin (stmt));
+  if (! BLOCK_ABSTRACT (stmt))
+    {
+      char begin_label[MAX_ARTIFICIAL_LABEL_BYTES];
+      char end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+      sprintf (begin_label, BLOCK_BEGIN_LABEL_FMT, next_block_number);
+      low_pc_attribute (begin_label);
+      sprintf (end_label, BLOCK_END_LABEL_FMT, next_block_number);
+      high_pc_attribute (end_label);
+    }
 }
 
 /* Output a DIE to represent a declared data object (either file-scope
@@ -2936,14 +3342,23 @@ output_local_variable_die (arg)
      register void *arg;
 {
   register tree decl = arg;
-  register tree type = TREE_TYPE (decl);
+  register tree origin = decl_ultimate_origin (decl);
 
   ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_local_variable);
   sibling_attribute ();
-  name_and_src_coords_attributes (decl);
-  member_attribute (DECL_CONTEXT (decl));
-  type_attribute (type, TREE_READONLY (decl), TREE_THIS_VOLATILE (decl));
-  location_or_const_value_attribute (decl);
+  if (origin != NULL)
+    abstract_origin_attribute (origin);
+  else
+    {
+      name_and_src_coords_attributes (decl);
+      member_attribute (DECL_CONTEXT (decl));
+      type_attribute (TREE_TYPE (decl),
+                     TREE_READONLY (decl), TREE_THIS_VOLATILE (decl));
+    }
+  if (DECL_ABSTRACT (decl))
+    equate_decl_number_to_die_number (decl);
+  else
+    location_or_const_value_attribute (decl);
 }
 
 static void
@@ -2968,13 +3383,8 @@ output_member_die (arg)
 }
 
 #if 0
-/* Don't generate either pointer_type DIEs or reference_type DIEs.  According
-   to the 4-4-90 Dwarf draft spec (just after requirement #47):
-
-       These two type entries are not currently generated by any compiler.
-       Since the only way to name a pointer (or reference) type is C or C++
-       is via a "typedef", an entry with the "typedef" tag is generated
-       instead.
+/* Don't generate either pointer_type DIEs or reference_type DIEs.  Use
+   modified types instead.
 
    We keep this code here just in case these types of DIEs may be needed
    to represent certain things in other languages (e.g. Pascal) someday.
@@ -3007,6 +3417,7 @@ output_reference_type_die (arg)
 }
 #endif
 
+static void
 output_ptr_to_mbr_type_die (arg)
      register void *arg;
 {
@@ -3040,6 +3451,8 @@ output_compile_unit_die (arg)
 
   if (strcmp (language_string, "GNU C++") == 0)
     language_attribute (LANG_C_PLUS_PLUS);
+  else if (strcmp (language_string, "GNU Ada") == 0)
+    language_attribute (LANG_ADA83);
   else if (flag_traditional)
     language_attribute (LANG_C);
   else
@@ -3077,8 +3490,7 @@ output_string_type_die (arg)
 
   /* Fudge the string length attribute for now.  */
 
-  string_length_attribute (
-       TYPE_MAX_VALUE (TYPE_DOMAIN (type)));
+  string_length_attribute (TYPE_MAX_VALUE (TYPE_DOMAIN (type)));
 }
 
 static void
@@ -3114,27 +3526,43 @@ output_local_subroutine_die (arg)
      register void *arg;
 {
   register tree decl = arg;
-  register tree type = TREE_TYPE (decl);
-  register tree return_type = TREE_TYPE (type);
-  char func_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+  register tree origin = decl_ultimate_origin (decl);
 
   ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_subroutine);
   sibling_attribute ();
   dienum_push ();
-  name_and_src_coords_attributes (decl);
-  inline_attribute (decl);
-  prototyped_attribute (type);
-  member_attribute (DECL_CONTEXT (decl));
-  type_attribute (return_type, 0, 0);
-
-  /* Avoid getting screwed up in cases where a function was declared static
-     but where no definition was ever given for it.  */
+  if (origin != NULL)
+    abstract_origin_attribute (origin);
+  else
+    {
+      register tree type = TREE_TYPE (decl);
 
-  if (TREE_ASM_WRITTEN (decl))
+      name_and_src_coords_attributes (decl);
+      inline_attribute (decl);
+      prototyped_attribute (type);
+      member_attribute (DECL_CONTEXT (decl));
+      type_attribute (TREE_TYPE (type), 0, 0);
+      pure_or_virtual_attribute (decl);
+    }
+  if (DECL_ABSTRACT (decl))
+    equate_decl_number_to_die_number (decl);
+  else
     {
-      low_pc_attribute (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
-      sprintf (func_end_label, FUNC_END_LABEL_FMT, current_funcdef_number);
-      high_pc_attribute (func_end_label);
+      /* Avoid getting screwed up in cases where a function was declared
+        static but where no definition was ever given for it.  */
+
+      if (TREE_ASM_WRITTEN (decl))
+       {
+         char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+         low_pc_attribute (IDENTIFIER_POINTER (DECL_ASSEMBLER_NAME (decl)));
+         sprintf (label, FUNC_END_LABEL_FMT, current_funcdef_number);
+         high_pc_attribute (label);
+         sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
+         body_begin_attribute (label);
+         sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
+         body_end_attribute (label);
+       }
     }
 }
 
@@ -3159,13 +3587,21 @@ output_typedef_die (arg)
      register void *arg;
 {
   register tree decl = arg;
-  register tree type = TREE_TYPE (decl);
+  register tree origin = decl_ultimate_origin (decl);
 
   ASM_OUTPUT_DWARF_TAG (asm_out_file, TAG_typedef);
   sibling_attribute ();
-  name_and_src_coords_attributes (decl);
-  member_attribute (DECL_CONTEXT (decl));
-  type_attribute (type, TREE_READONLY (decl), TREE_THIS_VOLATILE (decl));
+  if (origin != NULL)
+    abstract_origin_attribute (origin);
+  else
+    {
+      name_and_src_coords_attributes (decl);
+      member_attribute (DECL_CONTEXT (decl));
+      type_attribute (TREE_TYPE (decl),
+                     TREE_READONLY (decl), TREE_THIS_VOLATILE (decl));
+    }
+  if (DECL_ABSTRACT (decl))
+    equate_decl_number_to_die_number (decl);
 }
 
 static void
@@ -3306,7 +3742,7 @@ output_formal_types (function_or_method_type)
      register tree function_or_method_type;
 {
   register tree link;
-  register tree formal_type;
+  register tree formal_type = NULL;
   register tree first_parm_type = TYPE_ARG_TYPES (function_or_method_type);
 
   /* In the case where we are generating a formal types list for a C++
@@ -3380,32 +3816,22 @@ pend_type (type)
 
 /* Return non-zero if it is legitimate to output DIEs to represent a
    given type while we are generating the list of child DIEs for some
-   DIE associated with a given scope.
-
-   This function returns non-zero if *either* of the following two conditions
-   is satisfied:
+   DIE (e.g. a function or lexical block DIE) associated with a given scope.
 
-        o      the type actually belongs to the given scope (as evidenced
-               by its TYPE_CONTEXT value), or
-
-        o      the type is anonymous, and the `scope' in question is *not*
-               a RECORD_TYPE or UNION_TYPE.
-
-   In theory, we should be able to generate DIEs for anonymous types
-   *anywhere* (since the scope of an anonymous type is irrelevant)
-   however svr4 SDB doesn't want to see other type DIEs within the
-   lists of child DIEs for a TAG_structure_type or TAG_union_type DIE.
+   See the comments within the function for a description of when it is
+   considered legitimate to output DIEs for various kinds of types.
 
    Note that TYPE_CONTEXT(type) may be NULL (to indicate global scope)
    or it may point to a BLOCK node (for types local to a block), or to a
    FUNCTION_DECL node (for types local to the heading of some function
    definition), or to a FUNCTION_TYPE node (for types local to the
    prototyped parameter list of a function type specification), or to a
-   RECORD_TYPE or UNION_TYPE node (in the case of C++ nested types).
+   RECORD_TYPE, UNION_TYPE, or QUAL_UNION_TYPE node
+   (in the case of C++ nested types).
 
    The `scope' parameter should likewise be NULL or should point to a
    BLOCK node, a FUNCTION_DECL node, a FUNCTION_TYPE node, a RECORD_TYPE
-   node, or a UNION_TYPE node.
+   node, a UNION_TYPE node, or a QUAL_UNION_TYPE node.
 
    This function is used only for deciding when to "pend" and when to
    "un-pend" types to/from the pending_types_list.
@@ -3416,28 +3842,38 @@ pend_type (type)
    It order to delay the production of DIEs representing types of formal
    parameters, callers of this function supply `fake_containing_scope' as
    the `scope' parameter to this function.  Given that fake_containing_scope
-   is *not* the containing scope for *any* other type, the desired effect
-   is achieved, i.e. output of DIEs representing types is temporarily
-   suspended, and any type DIEs which would have been output otherwise
-   are instead placed onto the pending_types_list.  Later on, we can force
-   these (temporarily pended) types to be output simply by calling
+   is a tagged type which is *not* the containing scope for *any* other type,
+   the desired effect is achieved, i.e. output of DIEs representing types
+   is temporarily suspended, and any type DIEs which would have otherwise
+   been output are instead placed onto the pending_types_list.  Later on,
+   we force these (temporarily pended) types to be output simply by calling
    `output_pending_types_for_scope' with an actual argument equal to the
    true scope of the types we temporarily pended.
 */
 
-static int
+inline int
 type_ok_for_scope (type, scope)
     register tree type;
     register tree scope;
 {
-  return (TYPE_CONTEXT (type) == scope
-         || (TYPE_NAME (type) == NULL
-             && TREE_CODE (scope) != RECORD_TYPE
-             && TREE_CODE (scope) != UNION_TYPE));
+  /* Tagged types (i.e. struct, union, and enum types) must always be
+     output only in the scopes where they actually belong (or else the
+     scoping of their own tag names and the scoping of their member
+     names will be incorrect).  Non-tagged-types on the other hand can
+     generally be output anywhere, except that svr4 SDB really doesn't
+     want to see them nested within struct or union types, so here we
+     say it is always OK to immediately output any such a (non-tagged)
+     type, so long as we are not within such a context.  Note that the
+     only kinds of non-tagged types which we will be dealing with here
+     (for C and C++ anyway) will be array types and function types.  */
+
+  return is_tagged_type (type)
+        ? (TYPE_CONTEXT (type) == scope)
+        : (scope == NULL_TREE || ! is_tagged_type (scope));
 }
 
 /* Output any pending types (from the pending_types list) which we can output
-   now (given the limitations of the scope that we are working on now).
+   now (taking into account the scope that we are working on now).
 
    For each type output, remove the given type from the pending_types_list
    *before* we try to output it.
@@ -3496,7 +3932,7 @@ output_type (type, containing_scope)
      of this type (i.e. without any const or volatile qualifiers) so get
      the main variant (i.e. the unqualified version) of this type now.  */
 
-  type = TYPE_MAIN_VARIANT (type);
+  type = type_main_variant (type);
 
   if (TREE_ASM_WRITTEN (type))
     return;
@@ -3518,7 +3954,7 @@ output_type (type, containing_scope)
       case POINTER_TYPE:
       case REFERENCE_TYPE:
        /* For these types, all that is required is that we output a DIE
-          (or a set of DIEs) to represent that "basis" type.  */
+          (or a set of DIEs) to represent the "basis" type.  */
        output_type (TREE_TYPE (type), containing_scope);
        break;
 
@@ -3580,15 +4016,16 @@ output_type (type, containing_scope)
       case ENUMERAL_TYPE:
       case RECORD_TYPE:
       case UNION_TYPE:
+      case QUAL_UNION_TYPE:
 
        /* For a non-file-scope tagged type, we can always go ahead and
           output a Dwarf description of this type right now, even if
           the type in question is still incomplete, because if this
           local type *was* ever completed anywhere within its scope,
           that complete definition would already have been attached to
-          this RECORD_TYPE, UNION_TYPE or ENUMERAL_TYPE node by the
-          time we reach this point.  That's true because of the way the
-          front-end does its processing of file-scope declarations (of
+          this RECORD_TYPE, UNION_TYPE, QUAL_UNION_TYPE or ENUMERAL_TYPE
+          node by the time we reach this point.  That's true because of the
+          way the front-end does its processing of file-scope declarations (of
           functions and class types) within which other types might be
           nested.  The C and C++ front-ends always gobble up such "local
           scope" things en-mass before they try to output *any* debugging
@@ -3633,8 +4070,12 @@ output_type (type, containing_scope)
            break;
 
          case UNION_TYPE:
+         case QUAL_UNION_TYPE:
            output_die (output_union_type_die, type);
            break;
+
+         default:
+           abort ();   /* Should never happen.  */
          }
 
        /* If this is not an incomplete type, output descriptions of
@@ -3694,6 +4135,12 @@ output_type (type, containing_scope)
                }
            }
 
+           /* RECORD_TYPEs, UNION_TYPEs, and QUAL_UNION_TYPEs are themselves
+              scopes (at least in C++) so we must now output any nested
+              pending types which are local just to this type.  */
+
+           output_pending_types_for_scope (type);
+
            end_sibling_chain ();       /* Terminate member chain.  */
          }
 
@@ -3716,6 +4163,45 @@ output_type (type, containing_scope)
 
   TREE_ASM_WRITTEN (type) = 1;
 }
+
+static void
+output_tagged_type_instantiation (type)
+     register tree type;
+{
+  if (type == 0 || type == error_mark_node)
+    return;
+
+  /* We are going to output a DIE to represent the unqualified version of
+     of this type (i.e. without any const or volatile qualifiers) so make
+     sure that we have the main variant (i.e. the unqualified version) of
+     this type now.  */
+
+  assert (type == type_main_variant (type));
+
+  assert (TREE_ASM_WRITTEN (type));
+
+  switch (TREE_CODE (type))
+    {
+      case ERROR_MARK:
+       break;
+
+      case ENUMERAL_TYPE:
+       output_die (output_inlined_enumeration_type_die, type);
+       break;
+
+      case RECORD_TYPE:
+       output_die (output_inlined_structure_type_die, type);
+       break;
+
+      case UNION_TYPE:
+      case QUAL_UNION_TYPE:
+       output_die (output_inlined_union_type_die, type);
+       break;
+
+      default:
+       abort ();       /* Should never happen.  */
+    }
+}
 \f
 /* Output a TAG_lexical_block DIE followed by DIEs to represent all of
    the things which are local to the given block.  */
@@ -3724,33 +4210,67 @@ static void
 output_block (stmt)
     register tree stmt;
 {
-  register int have_significant_locals = 0;
+  register int must_output_die = 0;
+  register tree origin;
+  register enum tree_code origin_code;
 
   /* Ignore blocks never really used to make RTL.  */
 
   if (! stmt || ! TREE_USED (stmt))
     return;
 
-  /* Determine if this block contains any "significant" local declarations
-     which we need to output DIEs for.  */
+  /* 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.  */
 
-  if (BLOCK_INLINE_FUNCTION (stmt))
-    /* The outer scopes for inlinings *must* always be represented.  */
-    have_significant_locals = 1;
-  else
-    if (debug_info_level > DINFO_LEVEL_TERSE)
-      have_significant_locals = (BLOCK_VARS (stmt) != NULL);
-    else
-      {
-        register tree decl;
+  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.  */
 
-       for (decl = BLOCK_VARS (stmt); decl; decl = TREE_CHAIN (decl))
-         if (TREE_CODE (decl) == FUNCTION_DECL && DECL_INITIAL (decl))
+  if (origin_code == FUNCTION_DECL)
+    /* The outer scopes for inlinings *must* always be represented.  We
+       generate 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 (origin == NULL || ! is_body_block (origin))
+       {
+         /* 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);
+         else
            {
-             have_significant_locals = 1;
-             break;
+             register tree decl;
+
+             /* We are in terse mode, so only local (nested) function
+                definitions count as "significant" local declarations.  */
+
+             for (decl = BLOCK_VARS (stmt); decl; 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 TAG_lexical_block
      DIE for any block which contains no significant local declarations
@@ -3760,11 +4280,11 @@ output_block (stmt)
      a "significant" local declaration gets restricted to include only
      inlined function instances and local (nested) function definitions.  */
 
-  if (have_significant_locals)
+  if (must_output_die)
     {
-      output_die (BLOCK_INLINE_FUNCTION (stmt)
-                       ? output_inlined_subroutine_die
-                       : output_lexical_block_die,
+      output_die ((origin_code == FUNCTION_DECL)
+                   ? output_inlined_subroutine_die
+                   : output_lexical_block_die,
                  stmt);
       output_decls_for_scope (stmt);
       end_sibling_chain ();
@@ -3785,7 +4305,8 @@ output_decls_for_scope (stmt)
   if (! stmt || ! TREE_USED (stmt))
     return;
 
-  next_block_number++;
+  if (! BLOCK_ABSTRACT (stmt))
+    next_block_number++;
 
   /* Output the DIEs to represent all of the data objects, functions,
      typedefs, and tagged types declared directly within this block
@@ -3820,6 +4341,12 @@ output_decl (decl, containing_scope)
      register tree decl;
      register tree containing_scope;
 {
+  /* Make a note of the decl node we are going to be working on.  We may
+     need to give the user the source coordinates of where it appeared in
+     case we notice (later on) that something about it looks screwy.  */
+
+  dwarf_last_decl = decl;
+
   if (TREE_CODE (decl) == ERROR_MARK)
     return;
 
@@ -3841,11 +4368,11 @@ output_decl (decl, containing_scope)
 
     case FUNCTION_DECL:
       /* If we are in terse mode, don't output any DIEs to represent
-        mere external function declarations.  Also, if we are conforming
+        mere function declarations.  Also, if we are conforming
         to the DWARF version 1 specification, don't output DIEs for
-        mere external function declarations.  */
+        mere function declarations.  */
 
-      if (TREE_EXTERNAL (decl))
+      if (DECL_INITIAL (decl) == NULL_TREE)
 #if (DWARF_VERSION > 1)
        if (debug_info_level <= DINFO_LEVEL_TERSE)
 #endif
@@ -3872,7 +4399,7 @@ output_decl (decl, containing_scope)
 
       /* Now output a DIE to represent the function itself.  */
 
-      output_die (TREE_PUBLIC (decl) || TREE_EXTERNAL (decl)
+      output_die (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl)
                                ? output_global_subroutine_die
                                : output_local_subroutine_die,
                  decl);
@@ -3888,28 +4415,16 @@ output_decl (decl, containing_scope)
         ends with a void_type_node then there should *not* be an ellipsis
         at the end.  */
 
-      /* In the case where we are describing an external function, all
+      /* In the case where we are describing a mere function declaration, all
         we need to do here (and all we *can* do here) is to describe
         the *types* of its formal parameters.  */
 
-      if (TREE_EXTERNAL (decl))
+      if (DECL_INITIAL (decl) == NULL_TREE)
        output_formal_types (TREE_TYPE (decl));
       else
        {
          register tree arg_decls = DECL_ARGUMENTS (decl);
 
-         /* In the case where the FUNCTION_DECL represents a C++ non-static
-            member function, skip over the first thing on the DECL_ARGUMENTS
-            chain.  It only represents the hidden `this pointer' parameter
-            and the debugger should know implicitly that non-static member
-            functions have such a thing, and should be able to figure out
-            exactly what the type of each `this pointer' is (from the
-            AT_member attribute of the parent TAG_subroutine DIE)  without
-            being explicitly told.  */
-
-         if (TREE_CODE (TREE_TYPE (decl)) == METHOD_TYPE)
-           arg_decls = TREE_CHAIN (arg_decls);
-
          {
            register tree last_arg;
 
@@ -4032,19 +4547,25 @@ output_decl (decl, containing_scope)
        if (outer_scope && TREE_CODE (outer_scope) != ERROR_MARK)
          {
            /* Note that here, `outer_scope' is a pointer to the outermost
-              BLOCK node created to represent the body of a function.
+              BLOCK node created to represent a function.
               This outermost BLOCK actually represents the outermost
               binding contour for the function, i.e. the contour in which
-              the function's formal parameters get declared.  Just within
-              this contour, there will be another (nested) BLOCK which
-              represents the function's outermost block.  We don't want
-              to generate a lexical_block DIE to represent the outermost
-              block of a function body, because that is not really an
+              the function's formal parameters and labels get declared.
+
+              Curiously, it appears that the front end doesn't actually
+              put the PARM_DECL nodes for the current function onto the
+              BLOCK_VARS list for this outer scope.  (They are strung
+              off of the DECL_ARGUMENTS list for the function instead.)
+              The BLOCK_VARS list for the `outer_scope' does provide us
+              with a list of the LABEL_DECL nodes for the function however,
+              and we output DWARF info for those here.
+
+              Just within the `outer_scope' there will be another BLOCK
+              node representing the function's outermost pair of curly
+              braces.  We musn't generate a lexical_block DIE for this
+              outermost pair of curly braces because that is not really an
               independent scope according to ANSI C rules.  Rather, it is
-              the same scope in which the parameters were declared and
-              for Dwarf, we do not generate a TAG_lexical_block DIE for
-              that scope.  We must however see to it that the LABEL_DECLs
-              associated with `outer_scope' get DIEs generated for them.  */
+              the same scope in which the parameters were declared.  */
 
            {
              register tree label;
@@ -4055,6 +4576,11 @@ output_decl (decl, containing_scope)
                output_decl (label, outer_scope);
            }
 
+           /* Note here that `BLOCK_SUBBLOCKS (outer_scope)' points to a
+              list of BLOCK nodes which is always only one element long.
+              That one element represents the outermost pair of curley
+              braces for the function body.  */
+
            output_decls_for_scope (BLOCK_SUBBLOCKS (outer_scope));
 
            /* Finally, force out any pending types which are local to the
@@ -4085,6 +4611,20 @@ output_decl (decl, containing_scope)
            || ! TYPE_USED_FOR_FUNCTION (TREE_TYPE (decl)))
           return;
 
+      /* In the special case of a null-named TYPE_DECL node (representing
+        the declaration of some type tag), if the given TYPE_DECL is
+        marked as having been instantiated from some other (original)
+        TYPE_DECL node (e.g. one which was generated within the original
+        definition of an inline function) we have to generate a special
+        (abbreviated) TAG_structure_type, TAG_union_type, or
+        TAG_enumeration-type DIE here.  */
+
+      if (! DECL_NAME (decl) && DECL_ABSTRACT_ORIGIN (decl))
+       {
+         output_tagged_type_instantiation (TREE_TYPE (decl));
+         return;
+       }
+
       output_type (TREE_TYPE (decl), containing_scope);
 
       /* Note that unlike the gcc front end (which generates a NULL named
@@ -4111,7 +4651,7 @@ output_decl (decl, containing_scope)
         generated any DIEs to represent mere external object declarations.  */
 
 #if (DWARF_VERSION <= 1)
-      if (TREE_EXTERNAL (decl) && ! TREE_PUBLIC (decl))
+      if (DECL_EXTERNAL (decl) && ! TREE_PUBLIC (decl))
        break;
 #endif
 
@@ -4132,7 +4672,7 @@ output_decl (decl, containing_scope)
         was already generated in the .debug_pubnames section sub-entry
         for this data object definition.  */
 
-      if (TREE_PUBLIC (decl))
+      if (TREE_PUBLIC (decl) && ! DECL_ABSTRACT (decl))
        {
          char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
@@ -4140,11 +4680,26 @@ output_decl (decl, containing_scope)
          ASM_OUTPUT_LABEL (asm_out_file, label);
        }
 
-      /* Now output the DIE to represent the data object itself.  */
+      /* Now output the DIE to represent the data object itself.  This gets
+        complicated because of the possibility that the VAR_DECL really
+        represents an inlined instance of a formal parameter for an inline
+        function.  */
 
-      output_die (TREE_PUBLIC (decl) || TREE_EXTERNAL (decl)
-                  ? output_global_variable_die : output_local_variable_die,
-                 decl);
+      {
+        register void (*func) ();
+       register tree origin = decl_ultimate_origin (decl);
+
+       if (origin != NULL && TREE_CODE (origin) == PARM_DECL)
+         func = output_formal_parameter_die;
+       else
+         {
+           if (TREE_PUBLIC (decl) || DECL_EXTERNAL (decl))
+             func = output_global_variable_die;
+           else
+             func = output_local_variable_die;
+         }
+       output_die (func, decl);
+      }
       break;
 
     case FIELD_DECL:
@@ -4202,23 +4757,45 @@ dwarfout_file_scope_decl (decl, set_finalizing)
         a builtin function.  Explicit programmer-supplied declarations of
         these same functions should NOT be ignored however.  */
 
-      if (TREE_EXTERNAL (decl) && DECL_FUNCTION_CODE (decl))
+      if (DECL_EXTERNAL (decl) && DECL_FUNCTION_CODE (decl))
         return;
 
-      /* Ignore this FUNCTION_DECL if it refers to a file-scope extern
-        function 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 (TREE_EXTERNAL (decl) && !TREE_USED (decl))
+      /* What we would really like to do here is to filter out all mere
+        file-scope declarations of file-scope functions which are never
+        referenced later within this translation unit (and keep all of
+        ones that *are* referenced later on) but we aren't clarvoiant,
+        so we have no idea which functions will be referenced in the
+        future (i.e. later on within the current translation unit).
+        So here we just ignore all file-scope function declarations
+        which are not also definitions.  If and when the debugger needs
+        to know something about these funcstion, it wil have to hunt
+        around and find the DWARF information associated with the
+        *definition* of the function.
+
+        Note that we can't just check `DECL_EXTERNAL' to find out which
+        FUNCTION_DECL nodes represent definitions and which ones represent
+        mere declarations.  We have to check `DECL_INITIAL' instead.  That's
+        because the C front-end supports some weird semantics for "extern
+        inline" function definitions.  These can get inlined within the
+        current translation unit (an thus, we need to generate DWARF info
+        for their abstract instances so that the DWARF info for the
+        concrete inlined instances can have something to refer to) but
+        the compiler never generates any out-of-lines instances of such
+        things (despite the fact that they *are* definitions).  The
+        important point is that the C front-end marks these "extern inline"
+        functions as DECL_EXTERNAL, but we need to generate DWARf for them
+        anyway.
+
+        Note that the C++ front-end also plays some similar games for inline
+        function definitions appearing within include files which also
+        contain `#pragma interface' pragmas.  */
+
+      if (DECL_INITIAL (decl) == NULL_TREE)
        return;
 
-      if (TREE_PUBLIC (decl) && ! TREE_EXTERNAL (decl))
+      if (TREE_PUBLIC (decl)
+         && ! DECL_EXTERNAL (decl)
+         && ! DECL_ABSTRACT (decl))
        {
          char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
@@ -4248,12 +4825,13 @@ dwarfout_file_scope_decl (decl, set_finalizing)
         lookup mechanism and cause it to miss things which really ought
         to be in scope at a given point.  */
 
-      if (TREE_EXTERNAL (decl) && !TREE_USED (decl))
+      if (DECL_EXTERNAL (decl) && !TREE_USED (decl))
        return;
 
       if (TREE_PUBLIC (decl)
-         && ! TREE_EXTERNAL (decl)
-         && GET_CODE (DECL_RTL (decl)) == MEM)
+         && ! DECL_EXTERNAL (decl)
+         && GET_CODE (DECL_RTL (decl)) == MEM
+         && ! DECL_ABSTRACT (decl))
        {
          char label[MAX_ARTIFICIAL_LABEL_BYTES];
 
@@ -4295,9 +4873,18 @@ dwarfout_file_scope_decl (decl, set_finalizing)
       break;
 
     case TYPE_DECL:
-      /* Don't generate any DIEs to represent the standard built-in types.  */
-
-      if (DECL_SOURCE_LINE (decl) == 0)
+      /* Don't bother trying to generate any DIEs to represent any of the
+        normal built-in types for the language we are compiling, except
+        in cases where the types in question are *not* DWARF fundamental
+        types.  We make an exception in the case of non-fundamental types
+        for the sake of objective C (and perhaps C++) because the GNU
+        front-ends for these languages may in fact create certain "built-in"
+        types which are (for example) RECORD_TYPEs.  In such cases, we
+        really need to output these (non-fundamental) types because other
+        DIEs may contain references to them.  */
+
+      if (DECL_SOURCE_LINE (decl) == 0
+         && type_is_fundamental (TREE_TYPE (decl)))
        return;
 
       /* If we are in terse mode, don't generate any DIEs to represent
@@ -4391,6 +4978,33 @@ dwarfout_label (insn)
     }
 }
 
+/* Output a marker (i.e. a label) for the point in the generated code where
+   the real body of the function begins (after parameters have been moved
+   to their home locations).  */
+
+void
+dwarfout_begin_function ()
+{
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+  text_section ();
+  sprintf (label, BODY_BEGIN_LABEL_FMT, current_funcdef_number);
+  ASM_OUTPUT_LABEL (asm_out_file, label);
+}
+
+/* Output a marker (i.e. a label) for the point in the generated code where
+   the real body of the function ends (just before the epilogue code).  */
+
+void
+dwarfout_end_function ()
+{
+  char label[MAX_ARTIFICIAL_LABEL_BYTES];
+
+  text_section ();
+  sprintf (label, BODY_END_LABEL_FMT, current_funcdef_number);
+  ASM_OUTPUT_LABEL (asm_out_file, label);
+}
+
 /* Output a marker (i.e. a label) for the absolute end of the generated code
    for a function definition.  This gets called *after* the epilogue code
    has been generated. */
@@ -4727,12 +5341,14 @@ dwarfout_init (asm_out_file, main_input_filename)
   ASM_OUTPUT_LABEL (asm_out_file, DATA_BEGIN_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
 
+#if 0 /* GNU C doesn't currently use .data1.  */
   /* Output a starting label for the .data1 section.  */
 
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_PUSH_SECTION (asm_out_file, DATA1_SECTION);
   ASM_OUTPUT_LABEL (asm_out_file, DATA1_BEGIN_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
+#endif
 
   /* Output a starting label for the .rodata section.  */
 
@@ -4741,12 +5357,14 @@ dwarfout_init (asm_out_file, main_input_filename)
   ASM_OUTPUT_LABEL (asm_out_file, RODATA_BEGIN_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
 
+#if 0 /* GNU C doesn't currently use .rodata1.  */
   /* Output a starting label for the .rodata1 section.  */
 
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_PUSH_SECTION (asm_out_file, RODATA1_SECTION);
   ASM_OUTPUT_LABEL (asm_out_file, RODATA1_BEGIN_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
+#endif
 
   /* Output a starting label for the .bss section.  */
 
@@ -4904,12 +5522,14 @@ dwarfout_finish ()
   ASM_OUTPUT_LABEL (asm_out_file, DATA_END_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
 
+#if 0 /* GNU C doesn't currently use .data1.  */
   /* Output a terminator label for the .data1 section.  */
 
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_PUSH_SECTION (asm_out_file, DATA1_SECTION);
   ASM_OUTPUT_LABEL (asm_out_file, DATA1_END_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
+#endif
 
   /* Output a terminator label for the .rodata section.  */
 
@@ -4918,12 +5538,14 @@ dwarfout_finish ()
   ASM_OUTPUT_LABEL (asm_out_file, RODATA_END_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
 
+#if 0 /* GNU C doesn't currently use .rodata1.  */
   /* Output a terminator label for the .rodata1 section.  */
 
   fputc ('\n', asm_out_file);
   ASM_OUTPUT_PUSH_SECTION (asm_out_file, RODATA1_SECTION);
   ASM_OUTPUT_LABEL (asm_out_file, RODATA1_END_LABEL);
   ASM_OUTPUT_POP_SECTION (asm_out_file);
+#endif
 
   /* Output a terminator label for the .bss section.  */
 
@@ -4998,17 +5620,21 @@ dwarfout_finish ()
       ASM_OUTPUT_DWARF_ADDR (asm_out_file, DATA_BEGIN_LABEL);
       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, DATA_END_LABEL, DATA_BEGIN_LABEL);
 
+#if 0 /* GNU C doesn't currently use .data1.  */
       ASM_OUTPUT_DWARF_ADDR (asm_out_file, DATA1_BEGIN_LABEL);
       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, DATA1_END_LABEL,
                                             DATA1_BEGIN_LABEL);
+#endif
 
       ASM_OUTPUT_DWARF_ADDR (asm_out_file, RODATA_BEGIN_LABEL);
       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, RODATA_END_LABEL,
                                             RODATA_BEGIN_LABEL);
 
+#if 0 /* GNU C doesn't currently use .rodata1.  */
       ASM_OUTPUT_DWARF_ADDR (asm_out_file, RODATA1_BEGIN_LABEL);
       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, RODATA1_END_LABEL,
                                             RODATA1_BEGIN_LABEL);
+#endif
 
       ASM_OUTPUT_DWARF_ADDR (asm_out_file, BSS_BEGIN_LABEL);
       ASM_OUTPUT_DWARF_DELTA4 (asm_out_file, BSS_END_LABEL, BSS_BEGIN_LABEL);