aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorTom Tromey <tom@tromey.com>2024-04-11 12:43:06 -0600
committerTom Tromey <tom@tromey.com>2024-05-14 13:28:40 -0600
commit383a3d99c361ff66b9b5bceb28c0ab9485cd1789 (patch)
treebf596d7d37a828e65fddb316e43107aeda985995
parent25113e2d040fad868409c3e17262ee007fc8658a (diff)
downloadgdb-383a3d99c361ff66b9b5bceb28c0ab9485cd1789.zip
gdb-383a3d99c361ff66b9b5bceb28c0ab9485cd1789.tar.gz
gdb-383a3d99c361ff66b9b5bceb28c0ab9485cd1789.tar.bz2
Fix C++ canonicalization of hex literals
Currently names like "x::y::z<1>" and "x::y::z<0x01>" canonicalize to different things. I think it's nicer for them to be the same. Differences between types can be done using suffixes like "ll" and "u" -- it's not really possible to implement C++ rules in the canoncalizer, because no gdbarch is available. Possibly gdb should even drop the type here and just represent all integers the same way in names. Approved-By: John Baldwin <jhb@FreeBSD.org>
-rw-r--r--gdb/cp-name-parser.y61
1 files changed, 56 insertions, 5 deletions
diff --git a/gdb/cp-name-parser.y b/gdb/cp-name-parser.y
index b254d63..a84051a 100644
--- a/gdb/cp-name-parser.y
+++ b/gdb/cp-name-parser.y
@@ -1336,8 +1336,35 @@ cpname_state::parse_number (const char *p, int len, int parsed_float,
return FLOAT;
}
- /* This treats 0x1 and 1 as different literals. We also do not
- automatically generate unsigned types. */
+ /* Note that we do not automatically generate unsigned types. This
+ can't be done because we don't have access to the gdbarch
+ here. */
+
+ int base = 10;
+ if (len > 1 && p[0] == '0')
+ {
+ if (p[1] == 'x' || p[1] == 'X')
+ {
+ base = 16;
+ p += 2;
+ len -= 2;
+ }
+ else if (p[1] == 'b' || p[1] == 'B')
+ {
+ base = 2;
+ p += 2;
+ len -= 2;
+ }
+ else if (p[1] == 'd' || p[1] == 'D' || p[1] == 't' || p[1] == 'T')
+ {
+ /* Apparently gdb extensions. */
+ base = 10;
+ p += 2;
+ len -= 2;
+ }
+ else
+ base = 8;
+ }
long_p = 0;
unsigned_p = 0;
@@ -1358,6 +1385,24 @@ cpname_state::parse_number (const char *p, int len, int parsed_float,
break;
}
+ /* Use gdb_mpz here in case a 128-bit value appears. */
+ gdb_mpz value (0);
+ for (int off = 0; off < len; ++off)
+ {
+ int dig;
+ if (ISDIGIT (p[off]))
+ dig = p[off] - '0';
+ else
+ dig = TOLOWER (p[off]) - 'a' + 10;
+ if (dig >= base)
+ return ERROR;
+ value *= base;
+ value += dig;
+ }
+
+ std::string printed = value.str ();
+ const char *copy = obstack_strdup (&demangle_info->obstack, printed);
+
if (long_p == 0)
{
if (unsigned_p)
@@ -1380,10 +1425,10 @@ cpname_state::parse_number (const char *p, int len, int parsed_float,
type = make_builtin_type ("long long");
}
- name = make_name (p, len);
- lvalp->comp = fill_comp (literal_type, type, name);
+ name = make_name (copy, strlen (copy));
+ lvalp->comp = fill_comp (literal_type, type, name);
- return INT;
+ return INT;
}
static const char backslashable[] = "abefnrtv";
@@ -1990,6 +2035,12 @@ canonicalize_tests ()
should_be_the_same ("int short", "short");
should_be_the_same ("C<(char) 1>::m()", "C<(char) '\\001'>::m()");
+ should_be_the_same ("x::y::z<1>", "x::y::z<0x01>");
+ should_be_the_same ("x::y::z<1>", "x::y::z<01>");
+ should_be_the_same ("x::y::z<(unsigned long long) 1>", "x::y::z<01ull>");
+ should_be_the_same ("x::y::z<0b111>", "x::y::z<7>");
+ should_be_the_same ("x::y::z<0b111>", "x::y::z<0t7>");
+ should_be_the_same ("x::y::z<0b111>", "x::y::z<0D7>");
}
#endif