Hello,

This change makes GCC materialize subprogram renamings in Ada as imported declarations (DW_TAG_imported_declarations). For instance,

    procedure Foo renames Bar;

will output:

    DW_TAG_imported_declaration:
        DW_AT_name: foo
        DW_AT_import: <reference to Bar>

This new debugging information will let users reference the renamings instead of the renamed subprograms. This is in accordance with the DWARF specification: the section 3.2.3 (Imported (or Renamed) Declaration Entities) allows DW_TAG_imported_declaration DIEs to be used "as a general means to rename or provide an alias for an entity regardless of the context in which the importing declaration or the imported entity occur." (wording from the DWARFv3 and DWARFv4 specifications, allowed in DWARFv2).

gcc/ada/ChangeLog:

        * gcc-interface/decl.c (gnat_to_gnu_entity): Create
        IMPORTED_DECL nodes to describe the subprogram renamings which
        are relevant at debug time.
        * gcc-interface/gigi.h (get_debug_scope): Add declaration.
        * gcc-interface/trans.c (Identifier_to_gnu): Consider
        N_Defining_Operator_Symbol as valid entities.
        (gnat_to_gnu): Handle N_Defining_Operator_Symbol the same way as
        other entities.  Introduce a specific handling for
        N_Subprogram_Renaming_Declaration: call gnat_to_gnu_entity on
        the entity defined for relevant ones.
        (process_decls): Process subprogram renaming declarations during
        the second pass only.
        * gcc-interface/utils.c (get_debug_scope): Make it external.
        Consider N_Defining_Operator_Symbol as valid entities.
        (gnat_write_global_declarations): Output debugging information
        for top-level imported declarations.
        * namet.ads (Name_Equals): New function.
        * namet.adb (Name_Equals): New function.
        * namet.h (Name_Equals): New macro.  Declare Name_Equals from
        the Namet Ada unit.

gcc/ChangeLog:

        * dwarf2out.c (gen_decl_die): Generate DW_TAG_imported_* instead
        of DW_TAG_namespace for IMPORTED_DECL declarations.  Call
        dwarf2out_imported_module_or_decl_1 for all DWARF versions as
        this function already takes care of checking what it can emit.

Bootstrapped, regtested and checked with GDB's testsuite on x86_64-linux (GDB cannot use this yet but I'm about to submit a patch for it). Ok for trunk?

Thank you in advance for your feedback!

--
Pierre-Marie de Rodat
>From 8eed7558683e817755314d00adaf9b4820742d22 Mon Sep 17 00:00:00 2001
From: Pierre-Marie de Rodat <dero...@adacore.com>
Date: Wed, 22 Jul 2015 19:41:08 +0200
Subject: [PATCH] DWARF: materialize subprogram renamings in Ada as imported
 declarations

... so that debugger users can reference them instead of the renamed
subprograms.  This is in accordance with the DWARF specification: the
section 3.2.3 (Imported (or Renamed) Declaration Entities) allows
DW_TAG_imported_declaration DIEs to be used "as a general means to
rename or provide an alias for an entity regardless of the context in
which the importing declaration or the imported entity occur." (wording
from the DWARFv3 and DWARFv4 specifications, allowed in DWARFv2).

gcc/ada/ChangeLog:

	* gcc-interface/decl.c (gnat_to_gnu_entity): Create
	IMPORTED_DECL nodes to describe the subprogram renamings which
	are relevant at debug time.
	* gcc-interface/gigi.h (get_debug_scope): Add declaration.
	* gcc-interface/trans.c (Identifier_to_gnu): Consider
	N_Defining_Operator_Symbol as valid entities.
	(gnat_to_gnu): Handle N_Defining_Operator_Symbol the same way as
	other entities.  Introduce a specific handling for
	N_Subprogram_Renaming_Declaration: call gnat_to_gnu_entity on
	the entity defined for relevant ones.
	(process_decls): Process subprogram renaming declarations during
	the second pass only.
	* gcc-interface/utils.c (get_debug_scope): Make it external.
	Consider N_Defining_Operator_Symbol as valid entities.
	(gnat_write_global_declarations): Output debugging information
	for top-level imported declarations.
	* namet.ads (Name_Equals): New function.
	* namet.adb (Name_Equals): New function.
	* namet.h (Name_Equals): New macro.  Declare Name_Equals from
	the Namet Ada unit.

gcc/ChangeLog:

	* dwarf2out.c (gen_decl_die): Generate DW_TAG_imported_* instead
	of DW_TAG_namespace for IMPORTED_DECL declarations.  Call
	dwarf2out_imported_module_or_decl_1 for all DWARF versions as
	this function already takes care of checking what it can emit.

Bootstrapped, regtested and checked with GDB's testsuite on
x86_64-linux.
---
 gcc/ada/gcc-interface/decl.c  | 29 +++++++++++++++++++++++++++++
 gcc/ada/gcc-interface/gigi.h  |  5 +++++
 gcc/ada/gcc-interface/trans.c | 41 +++++++++++++++++++++++++++++++++++++++--
 gcc/ada/gcc-interface/utils.c | 18 +++++++++++++-----
 gcc/ada/namet.adb             | 30 ++++++++++++++++++++++++++++++
 gcc/ada/namet.ads             |  3 +++
 gcc/ada/namet.h               |  3 +++
 gcc/dwarf2out.c               |  6 +++++-
 8 files changed, 127 insertions(+), 8 deletions(-)

diff --git a/gcc/ada/gcc-interface/decl.c b/gcc/ada/gcc-interface/decl.c
index 971c066..ff54bc7 100644
--- a/gcc/ada/gcc-interface/decl.c
+++ b/gcc/ada/gcc-interface/decl.c
@@ -4126,6 +4126,8 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
 	   of its type, so we must elaborate that type now.  */
 	if (Present (Alias (gnat_entity)))
 	  {
+	    const Entity_Id gnat_renamed = Renamed_Entity (gnat_entity);
+
 	    if (Ekind (Alias (gnat_entity)) == E_Enumeration_Literal)
 	      gnat_to_gnu_entity (Etype (Alias (gnat_entity)), NULL_TREE, 0);
 
@@ -4138,6 +4140,33 @@ gnat_to_gnu_entity (Entity_Id gnat_entity, tree gnu_expr, int definition)
 	      if (Is_Itype (Etype (gnat_temp)))
 		gnat_to_gnu_entity (Etype (gnat_temp), NULL_TREE, 0);
 
+	    /* Materialize renamed subprograms in the debugging information
+	       when the renamed object is compile time known.  We can consider
+	       such renamings as imported declarations.
+
+	       Because the parameters in generic instantiations are often
+	       materialized as renamings, we ofter end up having both the
+	       renamed subprogram and the renaming in the same context and with
+	       the same name: in this case, renaming is both useless debug-wise
+	       and potentially harmful as name resolution in the debugger could
+	       return twice the same entity! So avoid this case.  */
+	    if (debug_info_p && !artificial_p
+		&& !(get_debug_scope (gnat_entity, NULL)
+		       == get_debug_scope (gnat_renamed, NULL)
+		     && Name_Equals (Chars (gnat_entity),
+				     Chars (gnat_renamed)))
+		&& Present (gnat_renamed)
+		&& (Ekind (gnat_renamed) == E_Function
+		    || Ekind (gnat_renamed) == E_Procedure)
+		&& gnu_decl != NULL_TREE
+		&& TREE_CODE (gnu_decl) == FUNCTION_DECL)
+	      {
+		tree decl = build_decl (input_location, IMPORTED_DECL,
+					gnu_entity_name, void_type_node);
+		IMPORTED_DECL_ASSOCIATED_DECL (decl) = gnu_decl;
+		gnat_pushdecl (decl, gnat_entity);
+	      }
+
 	    break;
 	  }
 
diff --git a/gcc/ada/gcc-interface/gigi.h b/gcc/ada/gcc-interface/gigi.h
index 67977b0..15d3d42 100644
--- a/gcc/ada/gcc-interface/gigi.h
+++ b/gcc/ada/gcc-interface/gigi.h
@@ -1007,6 +1007,11 @@ extern bool renaming_from_generic_instantiation_p (Node_Id gnat_node);
    don't have a GNU translation.  */
 extern void process_deferred_decl_context (bool force);
 
+/* Return the innermost scope, starting at GNAT_NODE relevant for the debug
+   info, or Empty if there is no such scope.  If not NULL, set IS_SUBPROGRAM to
+   whether the returned entity is a subprogram.  */
+extern Entity_Id get_debug_scope (Node_Id gnat_node, bool *is_subprogram);
+
 #ifdef __cplusplus
 extern "C" {
 #endif
diff --git a/gcc/ada/gcc-interface/trans.c b/gcc/ada/gcc-interface/trans.c
index 413550a..90a4667 100644
--- a/gcc/ada/gcc-interface/trans.c
+++ b/gcc/ada/gcc-interface/trans.c
@@ -1047,7 +1047,8 @@ Identifier_to_gnu (Node_Id gnat_node, tree *gnu_result_type_p)
      original type. Similarly, a class-wide type is equivalent to a subtype of
      itself. Finally, if the types are Itypes, one may be a copy of the other,
      which is also legal.  */
-  gnat_temp = (Nkind (gnat_node) == N_Defining_Identifier
+  gnat_temp = ((Nkind (gnat_node) == N_Defining_Identifier
+		|| Nkind (gnat_node) == N_Defining_Operator_Symbol)
 	       ? gnat_node : Entity (gnat_node));
   gnat_temp_type = Etype (gnat_temp);
 
@@ -5620,6 +5621,7 @@ gnat_to_gnu (Node_Id gnat_node)
     case N_Expanded_Name:
     case N_Operator_Symbol:
     case N_Defining_Identifier:
+    case N_Defining_Operator_Symbol:
       gnu_result = Identifier_to_gnu (gnat_node, &gnu_result_type);
 
       /* If atomic access is required on the RHS, build the atomic load.  */
@@ -5883,13 +5885,39 @@ gnat_to_gnu (Node_Id gnat_node)
 	}
       break;
 
+    case N_Subprogram_Renaming_Declaration:
+      {
+	const Node_Id gnat_renaming = Defining_Entity (gnat_node);
+	const Node_Id gnat_renamed = Renamed_Entity (gnat_renaming);
+
+	gnu_result = alloc_stmt_list ();
+
+	/* Materializing renamed subprograms will only benefit the debugging
+	   information as they aren't referenced in the generated code.  So
+	   skip them when they aren't needed.  Avoid doing this if:
+
+	     - there is a freeze node: in this case the renamed entity is not
+	       elaborated yet;
+	     - the renamed subprogram is intrinsic: it will not be available in
+	       the debugging information (note that both or only one of the
+	       renaming and the renamed subprograms can be intrinsic).  */
+	if (No (Freeze_Node (gnat_renaming))
+	    && Needs_Debug_Info (gnat_renaming)
+	    && Present (gnat_renamed)
+	    && (Ekind (gnat_renamed) == E_Function
+		|| Ekind (gnat_renamed) == E_Procedure)
+	    && !Is_Intrinsic_Subprogram (gnat_renaming)
+	    && !Is_Intrinsic_Subprogram (gnat_renamed))
+	  gnat_to_gnu_entity (gnat_renaming, gnat_to_gnu (gnat_renamed), 1);
+	break;
+      }
+
     case N_Implicit_Label_Declaration:
       gnat_to_gnu_entity (Defining_Entity (gnat_node), NULL_TREE, 1);
       gnu_result = alloc_stmt_list ();
       break;
 
     case N_Number_Declaration:
-    case N_Subprogram_Renaming_Declaration:
     case N_Package_Renaming_Declaration:
       /* These are fully handled in the front end.  */
       /* ??? For package renamings, find a way to use GENERIC namespaces so
@@ -8477,6 +8505,12 @@ process_decls (List_Id gnat_decls, List_Id gnat_decls2,
 		     || Nkind (gnat_decl) == N_Protected_Body_Stub)
 	      ;
 
+	    /* Renamed subprograms may not be elaborated yet at this point
+	       since renamings do not trigger freezing.  Wait for the second
+	       pass to take care of them.  */
+	    else if (Nkind (gnat_decl) == N_Subprogram_Renaming_Declaration)
+	      ;
+
 	    else
 	      add_stmt (gnat_to_gnu (gnat_decl));
 	  }
@@ -8505,6 +8539,9 @@ process_decls (List_Id gnat_decls, List_Id gnat_decls2,
 
 	    else if (Nkind (gnat_decl) == N_Freeze_Entity)
 	      process_decls (Actions (gnat_decl), Empty, Empty, false, true);
+
+	    else if (Nkind (gnat_decl) == N_Subprogram_Renaming_Declaration)
+	      add_stmt (gnat_to_gnu (gnat_decl));
 	  }
 }
 
diff --git a/gcc/ada/gcc-interface/utils.c b/gcc/ada/gcc-interface/utils.c
index 0032839..f209f54 100644
--- a/gcc/ada/gcc-interface/utils.c
+++ b/gcc/ada/gcc-interface/utils.c
@@ -594,11 +594,11 @@ gnat_set_type_context (tree type, tree context)
     }
 }
 
-/* Return the innermost scope, starting at GNAT_NODE, we are be interested in
-   the debug info, or Empty if there is no such scope.  If not NULL, set
-   IS_SUBPROGRAM to whether the returned entity is a subprogram.  */
+/* Return the innermost scope, starting at GNAT_NODE relevant for the debug
+   info, or Empty if there is no such scope.  If not NULL, set IS_SUBPROGRAM to
+   whether the returned entity is a subprogram.  */
 
-static Entity_Id
+Entity_Id
 get_debug_scope (Node_Id gnat_node, bool *is_subprogram)
 {
   Entity_Id gnat_entity;
@@ -606,7 +606,8 @@ get_debug_scope (Node_Id gnat_node, bool *is_subprogram)
   if (is_subprogram)
     *is_subprogram = false;
 
-  if (Nkind (gnat_node) == N_Defining_Identifier)
+  if (Nkind (gnat_node) == N_Defining_Identifier
+      || Nkind (gnat_node) == N_Defining_Operator_Symbol)
     gnat_entity = Scope (gnat_node);
   else
     return Empty;
@@ -5239,6 +5240,13 @@ gnat_write_global_declarations (void)
   FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter)
     if (TREE_CODE (iter) == VAR_DECL)
       rest_of_decl_compilation (iter, true, 0);
+
+  /* Output the imported modules/declarations.  In GNAT, these are only
+     materializing subprogram.  */
+  FOR_EACH_VEC_SAFE_ELT (global_decls, i, iter)
+   if (TREE_CODE (iter) == IMPORTED_DECL && !DECL_IGNORED_P (iter))
+     debug_hooks->imported_module_or_decl (iter, DECL_NAME (iter),
+					   DECL_CONTEXT (iter), 0);
 }
 
 /* ************************************************************************
diff --git a/gcc/ada/namet.adb b/gcc/ada/namet.adb
index 6def9f2..cfaec6e 100644
--- a/gcc/ada/namet.adb
+++ b/gcc/ada/namet.adb
@@ -1639,6 +1639,36 @@ package body Namet is
       end if;
    end Write_Name_Decoded;
 
+   -----------------
+   -- Name_Equals --
+   -----------------
+
+   function Name_Equals (N1, N2 : Name_Id) return Boolean is
+   begin
+      if N1 = N2 then
+         return True;
+      end if;
+
+      declare
+         L1 : constant Int := Int (Name_Entries.Table (N1).Name_Len);
+         L2 : constant Int := Int (Name_Entries.Table (N2).Name_Len);
+      begin
+         if L1 /= L2 then
+            return False;
+         end if;
+
+         declare
+            use Name_Chars;
+
+            I1 : constant Int := Name_Entries.Table (N1).Name_Chars_Index;
+            I2 : constant Int := Name_Entries.Table (N2).Name_Chars_Index;
+         begin
+            return (Name_Chars.Table (1 + I1 .. I1 + L1)
+                    = Name_Chars.Table (1 + I2 .. I2 + L2));
+         end;
+      end;
+   end Name_Equals;
+
 --  Package initialization, initialize tables
 
 begin
diff --git a/gcc/ada/namet.ads b/gcc/ada/namet.ads
index 4a21ef5..4a17e6e 100644
--- a/gcc/ada/namet.ads
+++ b/gcc/ada/namet.ads
@@ -561,6 +561,9 @@ package Namet is
    --  described for Get_Decoded_Name_String, and the resulting value stored
    --  in Name_Len and Name_Buffer is the decoded name.
 
+   function Name_Equals (N1, N2 : Name_Id) return Boolean;
+   --  Return whether N1 and N2 denote the same character sequence
+
    ------------------------------
    -- File and Unit Name Types --
    ------------------------------
diff --git a/gcc/ada/namet.h b/gcc/ada/namet.h
index 1ca589b..fe187b2 100644
--- a/gcc/ada/namet.h
+++ b/gcc/ada/namet.h
@@ -88,6 +88,9 @@ Get_Decoded_Name_String (Name_Id Id)
   return Name_Buffer;
 }
 
+#define Name_Equals namet__name_equals
+extern Boolean Name_Equals (Name_Id, Name_Id);
+
 /* Like Get_Decoded_Name_String, but the result has all qualification and
    package body entity suffixes stripped, and also all letters are upper
    cased.  This is used for building the enumeration literal table. */
diff --git a/gcc/dwarf2out.c b/gcc/dwarf2out.c
index 2834d57..bd93530 100644
--- a/gcc/dwarf2out.c
+++ b/gcc/dwarf2out.c
@@ -21527,11 +21527,15 @@ gen_decl_die (tree decl, tree origin, dw_die_ref context_die)
 				       context_die);
 
     case NAMESPACE_DECL:
-    case IMPORTED_DECL:
       if (dwarf_version >= 3 || !dwarf_strict)
 	gen_namespace_die (decl, context_die);
       break;
 
+    case IMPORTED_DECL:
+      dwarf2out_imported_module_or_decl_1 (decl, DECL_NAME (decl),
+					   DECL_CONTEXT (decl), context_die);
+      break;
+
     case NAMELIST_DECL:
       gen_namelist_decl (DECL_NAME (decl), context_die,
 			 NAMELIST_DECL_ASSOCIATED_DECL (decl));
-- 
2.4.6

Reply via email to