DWARF: make it possible to emit debug info for declarations only
authorPierre-Marie de Rodat <derodat@adacore.com>
Wed, 21 Jun 2017 11:24:51 +0000 (11:24 +0000)
committerPierre-Marie de Rodat <pmderodat@gcc.gnu.org>
Wed, 21 Jun 2017 11:24:51 +0000 (11:24 +0000)
The DWARF back-end used to systematically ignore file-scope function and
variable declarations.  While this is justified in language like C/C++,
where such declarations can appear in several translation units and thus
bloat uselessly the debug info, this behavior is counter-productive in
languages with a well-defined module system.  Specifically, it prevents
the description of imported entities, that belong to foreign languages,
making them unavailable from debuggers.

Take for instance:

    package C_Binding is
        function My_C_Function (I : Integer) return Integer;
        pragma Import (C, My_C_Function, "my_c_function");
    end C_Binding;

This makes available for Ada programs the C function "my_c_function"
under the following name: C_Binding.My_C_Function.  When GCC compiles
it, though, it is represented as a FUNCTION_DECL node with DECL_EXTERNAL
set and a null DECL_INITIAL, which used to be discarded unconditionally
in the DWARF back-end.

This patch moves such filter from the DWARF back-end to the relevant
callers: passes.c:rest_of_decl_compilation and
godump.c:go_early_global_decl. It also This patch also updates the Ada
front-end to call debug hooks for functions such as in the above
example, so that we do generate debugging information for them.

gcc/
* dwarf2out.c (gen_decl_die): Remove the guard to skip file-scope
FUNCTION_DECL declarations.
(dwarf2out_early_global_decl): Remove the guard to skip FUNCTION_DECL
declarations.
(dwaf2out_decl): Likewise.
* godump.c (go_early_global_decl): Skip call to the real debug hook
for FUNCTION_DECL declarations.
* passes.c (rest_of_decl_compilation): Skip call to the
early_global_decl debug hook for FUNCTION_DECL declarations, unless
-fdump-go-spec is passed.

gcc/ada/
* gcc-interface/ada-tree.h (DECL_FUNCTION_IS_DEF): Update copyright
notice.  New macro.
* gcc-interface/trans.c (Subprogram_Body_to_gnu): Tag the subprogram
as a definition.
(Compilation_Unit_to_gnu): Tag the elaboration procedure as a
definition.
* gcc-interface/decl.c (gnat_to_gnu_entity): Tag declarations of
imported subprograms for the current compilation unit as
definitions.  Disable debug info for references to variables.
* gcc-interface/gigi.h (create_subprog_decl): Update declaration.
* gcc-interface/utils.c (gnat_pushdecl): Add external DECLs that are
not built-in functions to their binding scope.
(create_subprog_decl): Add a DEFINITION parameter.  If it is true, tag
the function as a definition.  Update all callers.
(gnat_write_global_declarations): Emit debug info for imported
functions.  Filter out external variables for which debug info
is disabled.

gcc/testsuite/
* gnat.dg/debug11_pkg.adb, gnat.dg/debug11_pkg.ads,
gnat.dg/debug11_pkg2.ads: New testcase.

From-SVN: r249449

14 files changed:
gcc/ChangeLog
gcc/ada/ChangeLog
gcc/ada/gcc-interface/ada-tree.h
gcc/ada/gcc-interface/decl.c
gcc/ada/gcc-interface/gigi.h
gcc/ada/gcc-interface/trans.c
gcc/ada/gcc-interface/utils.c
gcc/dwarf2out.c
gcc/godump.c
gcc/passes.c
gcc/testsuite/ChangeLog
gcc/testsuite/gnat.dg/debug11_pkg.adb [new file with mode: 0644]
gcc/testsuite/gnat.dg/debug11_pkg.ads [new file with mode: 0644]
gcc/testsuite/gnat.dg/debug11_pkg2.ads [new file with mode: 0644]

index 62f91e587a836e71b5a922814f804f80742e014e..0926a49f0d21e8de0090d320738322953e429fc4 100644 (file)
@@ -1,3 +1,16 @@
+2017-06-21  Pierre-Marie de Rodat  <derodat@adacore.com>
+
+       * dwarf2out.c (gen_decl_die): Remove the guard to skip file-scope
+       FUNCTION_DECL declarations.
+       (dwarf2out_early_global_decl): Remove the guard to skip FUNCTION_DECL
+       declarations.
+       (dwaf2out_decl): Likewise.
+       * godump.c (go_early_global_decl): Skip call to the real debug hook
+       for FUNCTION_DECL declarations.
+       * passes.c (rest_of_decl_compilation): Skip call to the
+       early_global_decl debug hook for FUNCTION_DECL declarations, unless
+       -fdump-go-spec is passed.
+
 2017-06-21  Marc Glisse  <marc.glisse@inria.fr>
 
        * config/i386/i386.c (struct builtin_isa): New field pure_p.
index 5fb0cdf50f2dea7a73646a86ac6da7aaa0eaa815..fce09a0666f99100f0df6f88f315adda46c5de4e 100644 (file)
@@ -1,3 +1,23 @@
+2017-06-21  Pierre-Marie de Rodat  <derodat@adacore.com>
+
+       * gcc-interface/ada-tree.h (DECL_FUNCTION_IS_DEF): Update copyright
+       notice.  New macro.
+       * gcc-interface/trans.c (Subprogram_Body_to_gnu): Tag the subprogram
+       as a definition.
+       (Compilation_Unit_to_gnu): Tag the elaboration procedure as a
+       definition.
+       * gcc-interface/decl.c (gnat_to_gnu_entity): Tag declarations of
+       imported subprograms for the current compilation unit as
+       definitions.  Disable debug info for references to variables.
+       * gcc-interface/gigi.h (create_subprog_decl): Update declaration.
+       * gcc-interface/utils.c (gnat_pushdecl): Add external DECLs that are
+       not built-in functions to their binding scope.
+       (create_subprog_decl): Add a DEFINITION parameter.  If it is true, tag
+       the function as a definition.  Update all callers.
+       (gnat_write_global_declarations): Emit debug info for imported
+       functions.  Filter out external variables for which debug info
+       is disabled.
+
 2017-06-15  Nicolas Boulenguez  <nicolas.boulenguez@free.fr>
 
        PR ada/81105
index a3d38b1b22e9fd2415fd4451f78919947c87451a..511a0bd81732c3039b7a9d7a162f2aca6ce87113 100644 (file)
@@ -6,7 +6,7 @@
  *                                                                          *
  *                              C Header File                               *
  *                                                                          *
- *          Copyright (C) 1992-2016, Free Software Foundation, Inc.         *
+ *          Copyright (C) 1992-2017, Free Software Foundation, Inc.         *
  *                                                                          *
  * GNAT is free software;  you can  redistribute it  and/or modify it under *
  * terms of the  GNU General Public License as published  by the Free Soft- *
@@ -463,6 +463,11 @@ do {                                                  \
    a discriminant of a discriminated type without default expression.  */
 #define DECL_INVARIANT_P(NODE) DECL_LANG_FLAG_4 (FIELD_DECL_CHECK (NODE))
 
+/* Nonzero in a FUNCTION_DECL if this is a definition, i.e. if it was created
+   by a call to gnat_to_gnu_entity with definition set to True.  */
+#define DECL_FUNCTION_IS_DEF(NODE) \
+  DECL_LANG_FLAG_4 (FUNCTION_DECL_CHECK (NODE))
+
 /* Nonzero in a VAR_DECL if it is a temporary created to hold the return
    value of a function call or 'reference to a function call.  */
 #define DECL_RETURN_VALUE_P(NODE) DECL_LANG_FLAG_5 (VAR_DECL_CHECK (NODE))
index eab244e910c176c888f3642c94583ddea215e798..83b9d0749fe3ccd12f4ce0e2124e43de21637806 100644 (file)
@@ -1392,7 +1392,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
              = create_var_decl (create_concat_name (gnat_entity, "ALIGN"),
                                 NULL_TREE, gnu_new_type, NULL_TREE,
                                 false, false, false, false, false,
-                                true, debug_info_p, NULL, gnat_entity);
+                                true, debug_info_p && definition, NULL,
+                                gnat_entity);
 
            /* Initialize the aligned field if we have an initializer.  */
            if (gnu_expr)
@@ -1441,7 +1442,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
                                      NULL_TREE, gnu_type, gnu_expr,
                                      const_flag, Is_Public (gnat_entity),
                                      imported_p || !definition, static_flag,
-                                     volatile_flag, true, debug_info_p,
+                                     volatile_flag, true,
+                                     debug_info_p && definition,
                                      NULL, gnat_entity);
                gnu_expr = build_unary_op (ADDR_EXPR, NULL_TREE, gnu_unc_var);
                TREE_CONSTANT (gnu_expr) = 1;
@@ -1492,8 +1494,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
          = create_var_decl (gnu_entity_name, gnu_ext_name, gnu_type,
                             gnu_expr, const_flag, Is_Public (gnat_entity),
                             imported_p || !definition, static_flag,
-                            volatile_flag, artificial_p, debug_info_p,
-                            attr_list, gnat_entity, !renamed_obj);
+                            volatile_flag, artificial_p,
+                            debug_info_p && definition, attr_list,
+                            gnat_entity, !renamed_obj);
        DECL_BY_REF_P (gnu_decl) = used_by_ref;
        DECL_POINTS_TO_READONLY_P (gnu_decl) = used_by_ref && inner_const_flag;
        DECL_CAN_NEVER_BE_NULL_P (gnu_decl) = Can_Never_Be_Null (gnat_entity);
@@ -1545,8 +1548,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
              = create_var_decl (gnu_entity_name, gnu_ext_name, gnu_type,
                                 gnu_expr, true, Is_Public (gnat_entity),
                                 !definition, static_flag, volatile_flag,
-                                artificial_p, debug_info_p, attr_list,
-                                gnat_entity, false);
+                                artificial_p, debug_info_p && definition,
+                                attr_list, gnat_entity, false);
 
            SET_DECL_CONST_CORRESPONDING_VAR (gnu_decl, gnu_corr_var);
          }
@@ -4083,7 +4086,9 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, bool definition)
                                         gnu_type, gnu_param_list,
                                         inline_status, public_flag,
                                         extern_flag, artificial_p,
-                                        debug_info_p, attr_list, gnat_entity);
+                                        debug_info_p,
+                                        definition && imported_p, attr_list,
+                                        gnat_entity);
 
                DECL_STUBBED_P (gnu_decl)
                  = (Convention (gnat_entity) == Convention_Stubbed);
index b1fb34ad6202be2a0e124aea786ac56df3ff488e..0e25b6129a3fa79d7e99eeb6dade1f44417bbf15 100644 (file)
@@ -720,6 +720,8 @@ extern tree create_label_decl (tree name, Node_Id gnat_node);
 
    DEBUG_INFO_P is true if we need to write debug information for it.
 
+   DEFINITION is true if the subprogram is to be considered as a definition.
+
    ATTR_LIST is the list of attributes to be attached to the subprogram.
 
    GNAT_NODE is used for the position of the decl.  */
@@ -728,7 +730,8 @@ extern tree create_subprog_decl (tree name, tree asm_name, tree type,
                                 enum inline_status_t inline_status,
                                 bool public_flag, bool extern_flag,
                                 bool artificial_p, bool debug_info_p,
-                                struct attrib *attr_list, Node_Id gnat_node);
+                                bool definition, struct attrib *attr_list,
+                                Node_Id gnat_node);
 
 /* Given a subprogram declaration DECL, its assembler name and its type,
    finish constructing the subprogram declaration from ASM_NAME and TYPE.  */
index 2542626d0ca86cdf382be189aef898495616828d..79d099538c96c2cb5e64609e38020d48037fef9a 100644 (file)
@@ -398,7 +398,7 @@ gigi (Node_Id gnat_root,
     = create_subprog_decl (get_identifier ("__gnat_malloc"), NULL_TREE,
                           ftype,
                           NULL_TREE, is_disabled, true, true, true, false,
-                          NULL, Empty);
+                          false, NULL, Empty);
   DECL_IS_MALLOC (malloc_decl) = 1;
 
   ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
@@ -406,7 +406,7 @@ gigi (Node_Id gnat_root,
     = create_subprog_decl (get_identifier ("__gnat_free"), NULL_TREE,
                           ftype,
                           NULL_TREE, is_disabled, true, true, true, false,
-                          NULL, Empty);
+                          false, NULL, Empty);
 
   ftype = build_function_type_list (ptr_type_node, ptr_type_node, sizetype,
                                    NULL_TREE);
@@ -414,7 +414,7 @@ gigi (Node_Id gnat_root,
     = create_subprog_decl (get_identifier ("__gnat_realloc"), NULL_TREE,
                           ftype,
                           NULL_TREE, is_disabled, true, true, true, false,
-                          NULL, Empty);
+                          false, NULL, Empty);
 
   /* This is used for 64-bit multiplication with overflow checking.  */
   int64_type = gnat_type_for_size (64, 0);
@@ -423,7 +423,7 @@ gigi (Node_Id gnat_root,
                           build_function_type_list (int64_type, int64_type,
                                                     int64_type, NULL_TREE),
                           NULL_TREE, is_disabled, true, true, true, false,
-                          NULL, Empty);
+                          false, NULL, Empty);
 
   /* Name of the _Parent field in tagged record types.  */
   parent_name_id = get_identifier (Get_Name_String (Name_uParent));
@@ -446,21 +446,21 @@ gigi (Node_Id gnat_root,
     = create_subprog_decl
       (get_identifier ("system__soft_links__get_jmpbuf_address_soft"),
        NULL_TREE, build_function_type_list (jmpbuf_ptr_type, NULL_TREE),
-       NULL_TREE, is_disabled, true, true, true, false, NULL, Empty);
+       NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty);
 
   set_jmpbuf_decl
     = create_subprog_decl
       (get_identifier ("system__soft_links__set_jmpbuf_address_soft"),
        NULL_TREE, build_function_type_list (void_type_node, jmpbuf_ptr_type,
                                            NULL_TREE),
-       NULL_TREE, is_disabled, true, true, true, false, NULL, Empty);
+       NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty);
 
   get_excptr_decl
     = create_subprog_decl
       (get_identifier ("system__soft_links__get_gnat_exception"), NULL_TREE,
        build_function_type_list (build_pointer_type (except_type_node),
                                 NULL_TREE),
-       NULL_TREE, is_disabled, true, true, true, false, NULL, Empty);
+       NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty);
 
   not_handled_by_others_decl = get_identifier ("not_handled_by_others");
   for (t = TYPE_FIELDS (except_type_node); t; t = DECL_CHAIN (t))
@@ -478,7 +478,7 @@ gigi (Node_Id gnat_root,
       (get_identifier ("__builtin_setjmp"), NULL_TREE,
        build_function_type_list (integer_type_node, jmpbuf_ptr_type,
                                 NULL_TREE),
-       NULL_TREE, is_disabled, true, true, true, false, NULL, Empty);
+       NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty);
   DECL_BUILT_IN_CLASS (setjmp_decl) = BUILT_IN_NORMAL;
   DECL_FUNCTION_CODE (setjmp_decl) = BUILT_IN_SETJMP;
 
@@ -488,7 +488,7 @@ gigi (Node_Id gnat_root,
     = create_subprog_decl
       (get_identifier ("__builtin_update_setjmp_buf"), NULL_TREE,
        build_function_type_list (void_type_node, jmpbuf_ptr_type, NULL_TREE),
-       NULL_TREE, is_disabled, true, true, true, false, NULL, Empty);
+       NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty);
   DECL_BUILT_IN_CLASS (update_setjmp_buf_decl) = BUILT_IN_NORMAL;
   DECL_FUNCTION_CODE (update_setjmp_buf_decl) = BUILT_IN_UPDATE_SETJMP_BUF;
 
@@ -500,14 +500,14 @@ gigi (Node_Id gnat_root,
   raise_nodefer_decl
     = create_subprog_decl
       (get_identifier ("__gnat_raise_nodefer_with_msg"), NULL_TREE, ftype,
-       NULL_TREE, is_disabled, true, true, true, false, NULL, Empty);
+       NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty);
 
   set_exception_parameter_decl
     = create_subprog_decl
       (get_identifier ("__gnat_set_exception_parameter"), NULL_TREE,
        build_function_type_list (void_type_node, ptr_type_node, ptr_type_node,
                                 NULL_TREE),
-       NULL_TREE, is_disabled, true, true, true, false, NULL, Empty);
+       NULL_TREE, is_disabled, true, true, true, false, false, NULL, Empty);
 
   /* Hooks to call when entering/leaving an exception handler.  */
   ftype = build_function_type_list (void_type_node, ptr_type_node, NULL_TREE);
@@ -515,26 +515,30 @@ gigi (Node_Id gnat_root,
   begin_handler_decl
     = create_subprog_decl (get_identifier ("__gnat_begin_handler"), NULL_TREE,
                           ftype, NULL_TREE,
-                          is_disabled, true, true, true, false, NULL, Empty);
+                          is_disabled, true, true, true, false, false, NULL,
+                          Empty);
   /* __gnat_begin_handler is a dummy procedure.  */
   TREE_NOTHROW (begin_handler_decl) = 1;
 
   end_handler_decl
     = create_subprog_decl (get_identifier ("__gnat_end_handler"), NULL_TREE,
                           ftype, NULL_TREE,
-                          is_disabled, true, true, true, false, NULL, Empty);
+                          is_disabled, true, true, true, false, false, NULL,
+                          Empty);
 
   unhandled_except_decl
     = create_subprog_decl (get_identifier ("__gnat_unhandled_except_handler"),
                           NULL_TREE, ftype, NULL_TREE,
-                          is_disabled, true, true, true, false, NULL, Empty);
+                          is_disabled, true, true, true, false, false, NULL,
+                          Empty);
 
   /* Indicate that it never returns.  */
   ftype = build_qualified_type (ftype, TYPE_QUAL_VOLATILE);
   reraise_zcx_decl
     = create_subprog_decl (get_identifier ("__gnat_reraise_zcx"), NULL_TREE,
                           ftype, NULL_TREE,
-                          is_disabled, true, true, true, false, NULL, Empty);
+                          is_disabled, true, true, true, false, false, NULL,
+                          Empty);
 
   /* Dummy objects to materialize "others" and "all others" in the exception
      tables.  These are exported by a-exexpr-gcc.adb, so see this unit for
@@ -573,7 +577,8 @@ gigi (Node_Id gnat_root,
       tree decl
        = create_subprog_decl
          (get_identifier ("__gnat_last_chance_handler"), NULL_TREE, ftype,
-          NULL_TREE, is_disabled, true, true, true, false, NULL, Empty);
+          NULL_TREE, is_disabled, true, true, true, false, false, NULL,
+          Empty);
       for (i = 0; i < (int) ARRAY_SIZE (gnat_raise_decls); i++)
        gnat_raise_decls[i] = decl;
     }
@@ -739,7 +744,7 @@ build_raise_check (int check, enum exception_info_kind kind)
   result
     = create_subprog_decl (get_identifier (Name_Buffer), NULL_TREE, ftype,
                           NULL_TREE, is_disabled, true, true, true, false,
-                          NULL, Empty);
+                          false, NULL, Empty);
 
   return result;
 }
@@ -3745,6 +3750,7 @@ Subprogram_Body_to_gnu (Node_Id gnat_node)
     = gnat_to_gnu_entity (gnat_subprog_id, NULL_TREE,
                          Acts_As_Spec (gnat_node)
                          && !present_gnu_tree (gnat_subprog_id));
+  DECL_FUNCTION_IS_DEF (gnu_subprog_decl) = true;
   gnu_result_decl = DECL_RESULT (gnu_subprog_decl);
   gnu_subprog_type = TREE_TYPE (gnu_subprog_decl);
   gnu_cico_list = TYPE_CI_CO_LIST (gnu_subprog_type);
@@ -5417,12 +5423,15 @@ Compilation_Unit_to_gnu (Node_Id gnat_node)
   const Entity_Id gnat_unit_entity = Defining_Entity (gnat_unit);
   Entity_Id gnat_entity;
   Node_Id gnat_pragma;
-  /* Make the decl for the elaboration procedure.  */
+  /* Make the decl for the elaboration procedure.  Emit debug info for it, so
+     that users can break into their elaboration code in debuggers.  Kludge:
+     don't consider it as a definition so that we have a line map for its body,
+     but no subprogram description in debug info. */
   tree gnu_elab_proc_decl
     = create_subprog_decl
       (create_concat_name (gnat_unit_entity, body_p ? "elabb" : "elabs"),
        NULL_TREE, void_ftype, NULL_TREE,
-       is_disabled, true, false, true, true, NULL, gnat_unit);
+       is_disabled, true, false, true, true, false, NULL, gnat_unit);
   struct elab_info *info;
 
   vec_safe_push (gnu_elab_proc_stack, gnu_elab_proc_decl);
@@ -6453,7 +6462,7 @@ gnat_to_gnu (Node_Id gnat_node)
                gnu_prefix = gnat_to_gnu (gnat_prefix);
                gnu_prefix = maybe_implicit_deref (gnu_prefix);
              }
-               
+
            gnu_result
              = build_component_ref (gnu_prefix, gnu_field,
                                     (Nkind (Parent (gnat_node))
@@ -6484,7 +6493,8 @@ gnat_to_gnu (Node_Id gnat_node)
                                 (Entity (Prefix (gnat_node)),
                                  attr == Attr_Elab_Body ? "elabb" : "elabs"),
                                 NULL_TREE, void_ftype, NULL_TREE, is_disabled,
-                                true, true, true, true, NULL, gnat_node);
+                                true, true, true, true, false, NULL,
+                                gnat_node);
 
        gnu_result = Attribute_to_gnu (gnat_node, &gnu_result_type, attr);
       }
index b8c5d3d31f6aad0846cfce226bb716ee4b949f41..9e656579dda2203a1bb8d6152c4cbf3c99606711 100644 (file)
@@ -763,11 +763,13 @@ gnat_pushdecl (tree decl, Node_Id gnat_node)
   if (!(TREE_CODE (decl) == TYPE_DECL
         && TREE_CODE (TREE_TYPE (decl)) == UNCONSTRAINED_ARRAY_TYPE))
     {
-      if (DECL_EXTERNAL (decl))
-       {
-         if (TREE_CODE (decl) == FUNCTION_DECL && DECL_BUILT_IN (decl))
-           vec_safe_push (builtin_decls, decl);
-       }
+      /* External declarations must go to the binding level they belong to.
+        This will make corresponding imported entities are available in the
+        debugger at the proper time.  */
+      if (DECL_EXTERNAL (decl)
+         && TREE_CODE (decl) == FUNCTION_DECL
+         && DECL_BUILT_IN (decl))
+       vec_safe_push (builtin_decls, decl);
       else if (global_bindings_p ())
        vec_safe_push (global_decls, decl);
       else
@@ -3189,6 +3191,8 @@ create_label_decl (tree name, Node_Id gnat_node)
 
    DEBUG_INFO_P is true if we need to write debug information for it.
 
+   DEFINITION is true if the subprogram is to be considered as a definition.
+
    ATTR_LIST is the list of attributes to be attached to the subprogram.
 
    GNAT_NODE is used for the position of the decl.  */
@@ -3197,7 +3201,8 @@ tree
 create_subprog_decl (tree name, tree asm_name, tree type, tree param_decl_list,
                     enum inline_status_t inline_status, bool public_flag,
                     bool extern_flag, bool artificial_p, bool debug_info_p,
-                    struct attrib *attr_list, Node_Id gnat_node)
+                    bool definition, struct attrib *attr_list,
+                    Node_Id gnat_node)
 {
   tree subprog_decl = build_decl (input_location, FUNCTION_DECL, name, type);
   DECL_ARGUMENTS (subprog_decl) = param_decl_list;
@@ -3208,6 +3213,8 @@ create_subprog_decl (tree name, tree asm_name, tree type, tree param_decl_list,
 
   if (!debug_info_p)
     DECL_IGNORED_P (subprog_decl) = 1;
+  if (definition)
+    DECL_FUNCTION_IS_DEF (subprog_decl) = 1;
 
   switch (inline_status)
     {
@@ -5523,10 +5530,22 @@ gnat_write_global_declarations (void)
     if (TREE_CODE (iter) == TYPE_DECL && !DECL_IGNORED_P (iter))
       debug_hooks->type_decl (iter, false);
 
+  /* Output imported functions.  */
+  FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter)
+    if (TREE_CODE (iter) == FUNCTION_DECL
+       && DECL_EXTERNAL (iter)
+       && DECL_INITIAL (iter) == NULL
+       && !DECL_IGNORED_P (iter)
+       && DECL_FUNCTION_IS_DEF (iter))
+      debug_hooks->early_global_decl (iter);
+
   /* Then output the global variables.  We need to do that after the debug
-     information for global types is emitted so that they are finalized.  */
+     information for global types is emitted so that they are finalized.  Skip
+     external global variables, unless we need to emit debug info for them:
+     this is useful for imported variables, for instance.  */
   FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter)
-    if (TREE_CODE (iter) == VAR_DECL)
+    if (TREE_CODE (iter) == VAR_DECL
+       && (!DECL_EXTERNAL (iter) || !DECL_IGNORED_P (iter)))
       rest_of_decl_compilation (iter, true, 0);
 
   /* Output the imported modules/declarations.  In GNAT, these are only
index 92444e3cd461558d9b7e13dbc16a5b484cb8579f..c277d27e8e81d4dd1ff86a31df55a1c604d5fde6 100644 (file)
@@ -25289,14 +25289,6 @@ gen_decl_die (tree decl, tree origin, struct vlr_context *ctx,
       break;
 
     case FUNCTION_DECL:
-      /* Don't output any DIEs to represent mere function declarations,
-        unless they are class members or explicit block externs.  */
-      if (DECL_INITIAL (decl_or_origin) == NULL_TREE
-          && DECL_FILE_SCOPE_P (decl_or_origin)
-         && (current_function_decl == NULL_TREE
-             || DECL_ARTIFICIAL (decl_or_origin)))
-       break;
-
 #if 0
       /* FIXME */
       /* This doesn't work because the C frontend sets DECL_ABSTRACT_ORIGIN
@@ -25501,11 +25493,6 @@ dwarf2out_early_global_decl (tree decl)
       tree save_fndecl = current_function_decl;
       if (TREE_CODE (decl) == FUNCTION_DECL)
        {
-         /* No cfun means the symbol has no body, so there's nothing
-            to emit.  */
-         if (!DECL_STRUCT_FUNCTION (decl))
-           goto early_decl_exit;
-
          /* For nested functions, make sure we have DIEs for the parents first
             so that all nested DIEs are generated at the proper scope in the
             first shot.  */
@@ -25522,7 +25509,6 @@ dwarf2out_early_global_decl (tree decl)
       if (TREE_CODE (decl) == FUNCTION_DECL)
        current_function_decl = save_fndecl;
     }
- early_decl_exit:
   symtab->global_info_ready = save;
 }
 
@@ -25761,42 +25747,6 @@ dwarf2out_decl (tree decl)
       return;
 
     case FUNCTION_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 clairvoyant, 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 functions,
-        it will have to hunt around and find the DWARF information associated
-        with the definition of the function.
-
-        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 (and 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 we are called from dwarf2out_abstract_function output a DIE
-        anyway.  We can end up here this way with early inlining and LTO
-        where the inlined function is output in a different LTRANS unit
-        or not at all.  */
-      if (DECL_INITIAL (decl) == NULL_TREE
-         && ! DECL_ABSTRACT_P (decl))
-       return;
-
       /* If we're a nested function, initially use a parent of NULL; if we're
         a plain function, this will be fixed up in decls_for_scope.  If
         we're a method, it will be ignored, since we already have a DIE.  */
index 4884deead80c282bf8705053a3d3ad5c5da59184..3e905319b8fcf20565c11ddc5cb6c707fc89563e 100644 (file)
@@ -504,7 +504,8 @@ static void
 go_early_global_decl (tree decl)
 {
   go_decl (decl);
-  real_debug_hooks->early_global_decl (decl);
+  if (TREE_CODE (decl) != FUNCTION_DECL || DECL_STRUCT_FUNCTION (decl) != NULL)
+    real_debug_hooks->early_global_decl (decl);
 }
 
 /* A global variable decl.  */
index 64493ba1688ba713ec446cf5cdf5247ac80e4744..374f6f77897644de89be0748a203e772fae4294d 100644 (file)
@@ -262,17 +262,18 @@ rest_of_decl_compilation (tree decl,
      finalize_compilation_unit (and by consequence, locally scoped
      symbols), or by rest_of_type_compilation below.
 
-     Also, pick up function prototypes, which will be mostly ignored
-     by the different early_global_decl() hooks, but will at least be
-     used by Go's hijack of the debug_hooks to implement
-     -fdump-go-spec.  */
+     For Go's hijack of the debug_hooks to implement -fdump-go-spec, pick up
+     function prototypes.  Go's debug_hooks will not forward them to the
+     wrapped hooks.  */
   if (!in_lto_p
       && (TREE_CODE (decl) != FUNCTION_DECL
          /* This will pick up function prototypes with no bodies,
             which are not visible in finalize_compilation_unit()
             while iterating with FOR_EACH_*_FUNCTION through the
             symbol table.  */
-         || !DECL_SAVED_TREE (decl))
+         || (flag_dump_go_spec != NULL
+             && !DECL_SAVED_TREE (decl)
+             && DECL_STRUCT_FUNCTION (decl) == NULL))
 
       /* We need to check both decl_function_context and
         current_function_decl here to make sure local extern
index c9650f6d6f2a39688181b6bf3447da6127fd0b34..a31bba470d2ff61328b19ff58ddc860dd574fec7 100644 (file)
@@ -1,3 +1,8 @@
+2017-06-21  Pierre-Marie de Rodat  <derodat@adacore.com>
+
+       * gnat.dg/debug11_pkg.adb, gnat.dg/debug11_pkg.ads,
+       gnat.dg/debug11_pkg2.ads: New testcase.
+
 2017-06-21  Marc Glisse  <marc.glisse@inria.fr>
 
        * gcc.target/i386/getround.c: New file.
diff --git a/gcc/testsuite/gnat.dg/debug11_pkg.adb b/gcc/testsuite/gnat.dg/debug11_pkg.adb
new file mode 100644 (file)
index 0000000..336f2fd
--- /dev/null
@@ -0,0 +1,26 @@
+--  { dg-options "-cargs -g -dA -margs" }
+--  { dg-final { scan-assembler "local_imported_func" } }
+--  { dg-final { scan-assembler "local_imported_var" } }
+--  { dg-final { scan-assembler "global_imported_func" } }
+--  { dg-final { scan-assembler "global_imported_var" } }
+--  { dg-final { scan-assembler-not "foreign_imported_func" } }
+--  { dg-final { scan-assembler-not "foreign_imported_var" } }
+
+with Debug11_Pkg2;
+
+package body Debug11_Pkg is
+
+   procedure Dummy is
+      Local_Imported_Var : Integer;
+      pragma Import (C, Local_Imported_Var, "imported_var");
+
+      function Local_Imported_Func return Integer;
+      pragma Import (C, Local_Imported_Func, "imported_func");
+   begin
+      Local_Imported_Var := Local_Imported_Func;
+      Global_Imported_Var := Global_Imported_Func;
+      Debug11_Pkg2.Foreign_Imported_Var :=
+         Debug11_Pkg2.Foreign_Imported_Func;
+   end Dummy;
+
+end Debug11_Pkg;
diff --git a/gcc/testsuite/gnat.dg/debug11_pkg.ads b/gcc/testsuite/gnat.dg/debug11_pkg.ads
new file mode 100644 (file)
index 0000000..dc45310
--- /dev/null
@@ -0,0 +1,11 @@
+package Debug11_Pkg is
+
+   Global_Imported_Var : Integer;
+   pragma Import (C, Global_Imported_Var, "imported_var");
+
+   function Global_Imported_Func return Integer;
+   pragma Import (C, Global_Imported_Func, "imported_func");
+
+   procedure Dummy;
+
+end Debug11_Pkg;
diff --git a/gcc/testsuite/gnat.dg/debug11_pkg2.ads b/gcc/testsuite/gnat.dg/debug11_pkg2.ads
new file mode 100644 (file)
index 0000000..350f51c
--- /dev/null
@@ -0,0 +1,9 @@
+package Debug11_Pkg2 is
+
+   Foreign_Imported_Var : Integer;
+   pragma Import (C, Foreign_Imported_Var, "imported_var");
+
+   function Foreign_Imported_Func return Integer;
+   pragma Import (C, Foreign_Imported_Func, "imported_func");
+
+end Debug11_Pkg2;