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