Patchwork Fix cast of character to enum type in Ada

login
register
mail settings
Submitter Tom Tromey
Date May 3, 2019, 6:21 p.m.
Message ID <20190503182120.11052-1-tromey@adacore.com>
Download mbox | patch
Permalink /patch/32499/
State New
Headers show

Comments

Tom Tromey - May 3, 2019, 6:21 p.m.
An internal bug report points out that, when a global character enum
type is used, casting fails, like:

    (gdb) print global_char_enum'('F')
    $1 = 70

The bug here turns out to be that enumerators are qualified, so for
example the mangled name might be "pck__QU48", rather than "QU48".

This patch fixes the problem by only examining the suffix of the
enumerator.  This is ok because the type is already known, and because
the mangling scheme ensures that there won't be clashes.

Tested on x86-64 Fedora 29.

gdb/ChangeLog
2019-05-03  Tom Tromey  <tromey@adacore.com>

	* ada-exp.y (convert_char_literal): Check suffix of each
	enumerator.

gdb/testsuite/ChangeLog
2019-05-03  Tom Tromey  <tromey@adacore.com>

	* gdb.ada/char_enum/pck.ads (Global_Enum_Type): New type.
	* gdb.ada/char_enum/foo.adb: Use Global_Enum_Type.
	* gdb.ada/char_enum.exp: Add test.
---
 gdb/ChangeLog                           |  5 +++++
 gdb/ada-exp.y                           | 10 +++++++++-
 gdb/testsuite/ChangeLog                 |  6 ++++++
 gdb/testsuite/gdb.ada/char_enum.exp     |  3 +--
 gdb/testsuite/gdb.ada/char_enum/foo.adb |  1 +
 gdb/testsuite/gdb.ada/char_enum/pck.ads |  1 +
 6 files changed, 23 insertions(+), 3 deletions(-)
Joel Brobecker - May 3, 2019, 10:04 p.m.
Hi Tom,

On Fri, May 03, 2019 at 12:21:20PM -0600, Tom Tromey wrote:
> An internal bug report points out that, when a global character enum
> type is used, casting fails, like:
> 
>     (gdb) print global_char_enum'('F')
>     $1 = 70
> 
> The bug here turns out to be that enumerators are qualified, so for
> example the mangled name might be "pck__QU48", rather than "QU48".

As an aside, I re-educated myself with how things are generated
for the more common type of enumeration litterals, and those too
are being prefixed; which, when I think of it, makes sense, because
it allows us to refer to them using their fully qualified name
as well.

> This patch fixes the problem by only examining the suffix of the
> enumerator.  This is ok because the type is already known, and because
> the mangling scheme ensures that there won't be clashes.
> 
> Tested on x86-64 Fedora 29.
> 
> gdb/ChangeLog
> 2019-05-03  Tom Tromey  <tromey@adacore.com>
> 
> 	* ada-exp.y (convert_char_literal): Check suffix of each
> 	enumerator.
> 
> gdb/testsuite/ChangeLog
> 2019-05-03  Tom Tromey  <tromey@adacore.com>
> 
> 	* gdb.ada/char_enum/pck.ads (Global_Enum_Type): New type.
> 	* gdb.ada/char_enum/foo.adb: Use Global_Enum_Type.
> 	* gdb.ada/char_enum.exp: Add test.

LGTM. Thanks for the patch!

Patch

diff --git a/gdb/ada-exp.y b/gdb/ada-exp.y
index efad85b19ad..2a53d49ac8f 100644
--- a/gdb/ada-exp.y
+++ b/gdb/ada-exp.y
@@ -1408,9 +1408,17 @@  convert_char_literal (struct type *type, LONGEST val)
     return val;
 
   xsnprintf (name, sizeof (name), "QU%02x", (int) val);
+  size_t len = strlen (name);
   for (f = 0; f < TYPE_NFIELDS (type); f += 1)
     {
-      if (strcmp (name, TYPE_FIELD_NAME (type, f)) == 0)
+      /* Check the suffix because an enum constant in a package will
+	 have a name like "pkg__QUxx".  This is safe enough because we
+	 already have the correct type, and because mangling means
+	 there can't be clashes.  */
+      const char *ename = TYPE_FIELD_NAME (type, f);
+      size_t elen = strlen (ename);
+
+      if (elen >= len && strcmp (name, ename + elen - len) == 0)
 	return TYPE_FIELD_ENUMVAL (type, f);
     }
   return val;
diff --git a/gdb/testsuite/gdb.ada/char_enum.exp b/gdb/testsuite/gdb.ada/char_enum.exp
index 4b35fcb5ac4..c37d696f66d 100644
--- a/gdb/testsuite/gdb.ada/char_enum.exp
+++ b/gdb/testsuite/gdb.ada/char_enum.exp
@@ -27,5 +27,4 @@  set bp_location [gdb_get_line_number "STOP" ${testdir}/foo.adb]
 runto "foo.adb:$bp_location"
 
 gdb_test "print Char_Enum_Type'('B')" "= 1 'B'"
-
-
+gdb_test "print pck.Global_Enum_Type'('Y')" "= 1 'Y'"
diff --git a/gdb/testsuite/gdb.ada/char_enum/foo.adb b/gdb/testsuite/gdb.ada/char_enum/foo.adb
index 95914da2cfc..cf7fb7d3399 100644
--- a/gdb/testsuite/gdb.ada/char_enum/foo.adb
+++ b/gdb/testsuite/gdb.ada/char_enum/foo.adb
@@ -18,6 +18,7 @@  with Pck; use Pck;
 procedure Foo is
    type Char_Enum_Type is ('A', 'B', 'C', 'D', 'E');
    Char : Char_Enum_Type := 'D';
+   Gchar : Global_Enum_Type := 'Z';
 begin
    Do_Nothing (Char'Address);  -- STOP
 end Foo;
diff --git a/gdb/testsuite/gdb.ada/char_enum/pck.ads b/gdb/testsuite/gdb.ada/char_enum/pck.ads
index 5dd03889dee..f952e1c31c1 100644
--- a/gdb/testsuite/gdb.ada/char_enum/pck.ads
+++ b/gdb/testsuite/gdb.ada/char_enum/pck.ads
@@ -16,6 +16,7 @@ 
 with System;
 
 package Pck is
+   type Global_Enum_Type is ('X', 'Y', 'Z');
    procedure Do_Nothing (A : System.Address);
 end Pck;