diff mbox

[6/6] (Ada) Fix resolving of homonym components in tagged types

Message ID 1536594128-6487-7-git-send-email-brobecker@adacore.com
State New
Headers show

Commit Message

Joel Brobecker Sept. 10, 2018, 3:42 p.m. UTC
From: Jerome Guitton <guitton@adacore.com>

ada_value_struct_elt is used when displaying a component (say, 'N') of
a record object (say, 'Obj') of type, say, 't1'. Now if Obj is tagged
(Ada parlance: "tagged types" are what other object-oriented languages
call "classes"), then 'N' may not be visible in the current view and
we need to look for it in its actual type. We do that at the same time
as resolving variable-length fields. This would typically be done by
the following call to ada_value_struct_elt, with the last parameter
check_tag set to 1:

      t1 = ada_to_fixed_type (ada_get_base_type (t1), NULL,
                              address, NULL, 1);

This is the general logic, but recently we introduced a special case
to handle homonyms. Different components may have the same name in a
tagged type.  For instance:

       type Top_T is tagged record
          N : Integer := 1;
       end record;

       type Middle_T is new Top.Top_T with record
          N : Character := 'a';
       end record;

Middle_T extends Top_T and both define a (different) component with
the same name ('N'). In such a case, using the actual type of a
Middle_T object would create a confusion, since we would have two
component 'N' in this actual type.

So, to handle homonyms, we convert t1 to the actual type *if
and only if* N cannot be found in the current view. For example, if Obj
has been created as a Middle_T but is seen as a Top_T'Class at our
point of execution, then "print Obj.N" will display the integer field
defined in Top_T's declaration.

Now, even if we find N in the current view, we still have to get a
fixed type: for instance, the record can be unconstrained and we still
need a fixed type to get the proper offset to each field. That is
to say, in this case:

   type Dyn_Top_T (Disc : Natural) is tagged record
      S : Integer_Array (1 .. Disc) := (others => Disc);
      N : Integer := 1;
   end record;

   type Dyn_Middle_T is new Dyn_Top.Dyn_Top_T with record
      N : Character := 'a';
      U : Integer := 42;
   end record;

If we have an object Obj of type Dyn_Middle_T and we want to display
U, we don't need to build, from its tag, a real type with all its real
fields. In other words, we don't need to add the parent components:
Disc, S, and the integer N. We only need to access U and it is
directly visible in Dyn_Middle_T. So no tag handling. However, we do
need to build a fixed-size type to have the proper offset to U (since
this offset to U depends on the size of Obj.S, which itself is dynamic
and depends on the value of Obj.Disc).

We accidentally lost some of this treatment when we introduced the
resolution of homonyms. This patch re-install this part by uncoupling
the tag resolution from the "fixing" of variable-length components.

This change also slightly simplifies the non-tagged case: in the
non-tagged case, no need to set check_tag to 1, since we already know
that there is no tag.

gdb/ChangeLog:

	* ada-lang.c (ada_value_struct_elt): Call ada_to_fixed_type
	with check_tag to 1 if and only if the type is tagged and the
	component being searched cannot been found in the current
	view. Otherwise, always call ada_to_fixed_type with
	check_tag to 0.

gdb/testsuite/ChangeLog:

	* gdb.ada/same_component_name: Add test for case of tagged record
	with variable-length fields.
---
 gdb/ChangeLog                                     |  8 ++++++++
 gdb/ada-lang.c                                    | 14 +++++++++----
 gdb/testsuite/ChangeLog                           |  5 +++++
 gdb/testsuite/gdb.ada/same_component_name.exp     | 10 +++++++++
 gdb/testsuite/gdb.ada/same_component_name/foo.adb | 11 +++++++---
 gdb/testsuite/gdb.ada/same_component_name/pck.adb | 15 ++++++++++++++
 gdb/testsuite/gdb.ada/same_component_name/pck.ads | 25 +++++++++++++++++++++++
 7 files changed, 81 insertions(+), 7 deletions(-)
diff mbox

Patch

diff --git a/gdb/ChangeLog b/gdb/ChangeLog
index 0c94ad4..392d77a 100644
--- a/gdb/ChangeLog
+++ b/gdb/ChangeLog
@@ -1,3 +1,11 @@ 
+2018-09-10  Jerome Guitton  <guitton@adacore.com>
+
+	* ada-lang.c (ada_value_struct_elt): Call ada_to_fixed_type
+	with check_tag to 1 if and only if the type is tagged and the
+	component being searched cannot been found in the current
+	view. Otherwise, always call ada_to_fixed_type with
+	check_tag to 0.
+
 2018-09-10  Xavier Roirand  <roirand@adacore.com>
 
 	* ada-lang.c (ada_is_access_to_unconstrained_array): Remove static
diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
index d151dde..1462271 100644
--- a/gdb/ada-lang.c
+++ b/gdb/ada-lang.c
@@ -7554,6 +7554,7 @@  ada_value_struct_elt (struct value *arg, const char *name, int no_err)
 {
   struct type *t, *t1;
   struct value *v;
+  int check_tag;
 
   v = NULL;
   t1 = t = ada_check_typedef (value_type (arg));
@@ -7617,12 +7618,17 @@  ada_value_struct_elt (struct value *arg, const char *name, int no_err)
           if (!find_struct_field (name, t1, 0,
                                   &field_type, &byte_offset, &bit_offset,
                                   &bit_size, NULL))
-	    t1 = ada_to_fixed_type (ada_get_base_type (t1), NULL,
-                                    address, NULL, 1);
+	    check_tag = 1;
+	  else
+	    check_tag = 0;
         }
       else
-        t1 = ada_to_fixed_type (ada_get_base_type (t1), NULL,
-                                address, NULL, 1);
+	check_tag = 0;
+
+      /* Convert to fixed type in all cases, so that we have proper
+	 offsets to each field in unconstrained record types.  */
+      t1 = ada_to_fixed_type (ada_get_base_type (t1), NULL,
+			      address, NULL, check_tag);
 
       if (find_struct_field (name, t1, 0,
                              &field_type, &byte_offset, &bit_offset,
diff --git a/gdb/testsuite/ChangeLog b/gdb/testsuite/ChangeLog
index bad86cf..fc18b22 100644
--- a/gdb/testsuite/ChangeLog
+++ b/gdb/testsuite/ChangeLog
@@ -1,3 +1,8 @@ 
+2018-09-10  Jerome Guitton  <guitton@adacore.com>
+
+	* gdb.ada/same_component_name: Add test for case of tagged record
+	with variable-length fields.
+
 2018-09-10  Xavier Roirand  <roirand@adacore.com>
 
 	* gdb.ada/access_to_unbounded_array.exp: New testcase.
diff --git a/gdb/testsuite/gdb.ada/same_component_name.exp b/gdb/testsuite/gdb.ada/same_component_name.exp
index 9069c2d..34e29c1 100644
--- a/gdb/testsuite/gdb.ada/same_component_name.exp
+++ b/gdb/testsuite/gdb.ada/same_component_name.exp
@@ -26,10 +26,12 @@  clean_restart ${testfile}
 set bp_top_location [gdb_get_line_number "BREAK_TOP" ${testdir}/pck.adb]
 set bp_middle_location [gdb_get_line_number "BREAK_MIDDLE" ${testdir}/pck.adb]
 set bp_bottom_location [gdb_get_line_number "BREAK_BOTTOM" ${testdir}/pck.adb]
+set bp_dyn_middle_location [gdb_get_line_number "BREAK_DYN_MIDDLE" ${testdir}/pck.adb]
 
 gdb_breakpoint "pck.adb:$bp_top_location"
 gdb_breakpoint "pck.adb:$bp_middle_location"
 gdb_breakpoint "pck.adb:$bp_bottom_location"
+gdb_breakpoint "pck.adb:$bp_dyn_middle_location"
 
 gdb_run_cmd
 
@@ -58,3 +60,11 @@  gdb_test "continue" \
 
 gdb_test "print obj.x" " = 6" \
          "Print field existing only in bottom component"
+
+gdb_test "continue" \
+         ".*Breakpoint $decimal, pck.dyn_middle.assign \\(.*\\).*" \
+         "continue to dyn_middle assign breakpoint"
+
+gdb_test "print obj.u" " = 42" \
+         "Print field existing only in dyn_middle component"
+
diff --git a/gdb/testsuite/gdb.ada/same_component_name/foo.adb b/gdb/testsuite/gdb.ada/same_component_name/foo.adb
index 84fe9f5..c7debe1 100644
--- a/gdb/testsuite/gdb.ada/same_component_name/foo.adb
+++ b/gdb/testsuite/gdb.ada/same_component_name/foo.adb
@@ -17,15 +17,20 @@  with Pck;
 use Pck;
 use Pck.Middle;
 use Pck.Top;
+use Pck.Dyn_Middle;
+use Pck.Dyn_Top;
 
 procedure Foo is
-   B : Bottom_T;
-   M : Middle_T;
-
+   B  : Bottom_T;
+   M  : Middle_T;
+   DM : Dyn_Middle_T (24);
 begin
    Assign (Top_T (B), 12);
    Assign (B, 10.0);
 
    Assign (M, 'V');
    Assign (B, 5.0);
+
+   Assign (Dyn_Top_T (DM), 12);
+   Assign (DM, 'V');
 end Foo;
diff --git a/gdb/testsuite/gdb.ada/same_component_name/pck.adb b/gdb/testsuite/gdb.ada/same_component_name/pck.adb
index fd638f7..a0d28b3 100644
--- a/gdb/testsuite/gdb.ada/same_component_name/pck.adb
+++ b/gdb/testsuite/gdb.ada/same_component_name/pck.adb
@@ -39,4 +39,19 @@  package body Pck is
    begin
       null;
    end Do_Nothing;
+
+   package body Dyn_Top is
+      procedure Assign (Obj: in out Dyn_Top_T; TV : Integer) is
+      begin
+         Do_Nothing (Obj'Address); -- BREAK_DYN_TOP
+      end Assign;
+   end Dyn_Top;
+
+   package body Dyn_Middle is
+      procedure Assign (Obj: in out Dyn_Middle_T; MV : Character) is
+      begin
+         Do_Nothing (Obj'Address); -- BREAK_DYN_MIDDLE
+      end Assign;
+   end Dyn_Middle;
+
 end Pck;
diff --git a/gdb/testsuite/gdb.ada/same_component_name/pck.ads b/gdb/testsuite/gdb.ada/same_component_name/pck.ads
index 961aee7..db1554d 100644
--- a/gdb/testsuite/gdb.ada/same_component_name/pck.ads
+++ b/gdb/testsuite/gdb.ada/same_component_name/pck.ads
@@ -48,4 +48,29 @@  package Pck is
 
    procedure Do_Nothing (A : System.Address);
 
+   type Integer_Array is array (Natural range <>) of Integer;
+
+   package Dyn_Top is
+      type Dyn_Top_T (Disc : Natural) is tagged private;
+      type Dyn_Top_A is access Dyn_Top_T'Class;
+      procedure Assign (Obj: in out Dyn_Top_T; TV : Integer);
+   private
+      type Dyn_Top_T (Disc : Natural) is tagged record
+         S : Integer_Array (1 .. Disc) := (others => Disc);
+         N : Integer := 1;
+         A : Integer := 48;
+      end record;
+   end Dyn_Top;
+
+   package Dyn_Middle is
+      type Dyn_Middle_T is new Dyn_Top.Dyn_Top_T with private;
+      type Dyn_Middle_A is access Dyn_Middle_T'Class;
+      procedure Assign (Obj: in out Dyn_Middle_T; MV : Character);
+   private
+      type Dyn_Middle_T is new Dyn_Top.Dyn_Top_T with record
+         N : Character := 'a';
+         U : Integer := 42;
+      end record;
+   end Dyn_Middle;
+
 end Pck;