OSDN Git Service

* pa.h (OVERRIDE_OPTIONS): Define. Give a warning if -fpic or
[pf3gnuchains/gcc-fork.git] / gcc / dwarfout.c
index 98f82a4..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,6 +81,12 @@ extern char *rindex ();
 #define ASM_COMMENT_START ";#"
 #endif
 
+/* 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
    function's return type or some formal parameter of some function.
@@ -277,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 ();
@@ -518,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
@@ -742,6 +762,26 @@ 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
@@ -750,7 +790,8 @@ is_tagged_type (type)
 {
   register enum tree_code code = TREE_CODE (type);
 
-  return (code == RECORD_TYPE || code == UNION_TYPE || code == ENUMERAL_TYPE);
+  return (code == RECORD_TYPE || code == UNION_TYPE
+         || code == QUAL_UNION_TYPE || code == ENUMERAL_TYPE);
 }
 
 static char *
@@ -874,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>";
     }
@@ -1294,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);
     }
 }
 
@@ -1357,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:
@@ -1431,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
@@ -1492,18 +1558,7 @@ output_mem_loc_descriptor (rtl)
           distinction between OP_REG and OP_BASEREG.  */
 
        ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_BASEREG);
-       {
-         register unsigned regno = REGNO (rtl);
-
-         if (regno >= FIRST_PSEUDO_REGISTER)
-           {
-             fprintf (stderr, "%s: regno botch detected: dwarfout.c:%u\n",
-                      language_string, __LINE__);
-             debug_rtx(rtl);
-             regno = 0;
-           }
-         ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DBX_REGISTER_NUMBER (regno));
-       }
+       output_reg_number (rtl);
        break;
 
       case MEM:
@@ -1558,18 +1613,7 @@ output_loc_descriptor (rtl)
 
     case REG:
        ASM_OUTPUT_DWARF_STACK_OP (asm_out_file, OP_REG);
-       {
-         register unsigned regno = REGNO (rtl);
-
-         if (regno >= FIRST_PSEUDO_REGISTER)
-           {
-             fprintf (stderr, "%s: regno botch detected: dwarfout.c:%u\n",
-                      language_string, __LINE__);
-             debug_rtx(rtl);
-             regno = 0;
-           }
-         ASM_OUTPUT_DWARF_DATA4 (asm_out_file, DBX_REGISTER_NUMBER (regno));
-       }
+       output_reg_number (rtl);
        break;
 
     case MEM:
@@ -1829,7 +1873,7 @@ field_byte_offset (decl)
      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 accomodate all of the bits of the bit-field itself.
+     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
@@ -1910,16 +1954,16 @@ location_attribute (rtl)
      don't do that.  Instead we output a zero-length location descriptor
      value as part of the location attribute.
 
-     A variable which has been optimized out of existance will have a
+     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 existance.
+     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 existance, we do not simply
+     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
@@ -2076,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 (rtl == NULL)
+       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_RTX)
     return;
 
   switch (GET_CODE (rtl))
@@ -2368,6 +2453,7 @@ 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;
 
@@ -2538,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.  */
 
@@ -2785,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
@@ -3094,11 +3209,15 @@ output_global_subroutine_die (arg)
     {
       if (! DECL_EXTERNAL (decl))
        {
-         char func_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+         char 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);
+         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);
        }
     }
 }
@@ -3332,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
@@ -3432,11 +3553,15 @@ output_local_subroutine_die (arg)
 
       if (TREE_ASM_WRITTEN (decl))
        {
-         char func_end_label[MAX_ARTIFICIAL_LABEL_BYTES];
+         char 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);
+         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);
        }
     }
 }
@@ -3701,11 +3826,12 @@ pend_type (type)
    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.
@@ -3806,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;
@@ -3828,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;
 
@@ -3890,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
@@ -3943,6 +4070,7 @@ output_type (type, containing_scope)
            break;
 
          case UNION_TYPE:
+         case QUAL_UNION_TYPE:
            output_die (output_union_type_die, type);
            break;
 
@@ -4007,9 +4135,9 @@ output_type (type, containing_scope)
                }
            }
 
-           /* RECORD_TYPEs and UNION_TYPEs are themselves scopes (at least
-              in C++) so we must now output any nested pending types which
-              are local just to this RECORD_TYPE or UNION_TYPE.  */
+           /* 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);
 
@@ -4048,7 +4176,7 @@ output_tagged_type_instantiation (type)
      sure that we have the main variant (i.e. the unqualified version) of
      this type now.  */
 
-  assert (type == TYPE_MAIN_VARIANT (type));
+  assert (type == type_main_variant (type));
 
   assert (TREE_ASM_WRITTEN (type));
 
@@ -4066,6 +4194,7 @@ output_tagged_type_instantiation (type)
        break;
 
       case UNION_TYPE:
+      case QUAL_UNION_TYPE:
        output_die (output_inlined_union_type_die, type);
        break;
 
@@ -4212,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;
 
@@ -4233,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 (DECL_EXTERNAL (decl))
+      if (DECL_INITIAL (decl) == NULL_TREE)
 #if (DWARF_VERSION > 1)
        if (debug_info_level <= DINFO_LEVEL_TERSE)
 #endif
@@ -4280,11 +4415,11 @@ 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 (DECL_EXTERNAL (decl))
+      if (DECL_INITIAL (decl) == NULL_TREE)
        output_formal_types (TREE_TYPE (decl));
       else
        {
@@ -4625,17 +4760,37 @@ dwarfout_file_scope_decl (decl, set_finalizing)
       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 (DECL_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)
@@ -4718,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
@@ -4814,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. */
@@ -5150,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.  */
 
@@ -5164,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.  */
 
@@ -5327,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.  */
 
@@ -5341,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.  */
 
@@ -5421,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);