Fix gdb.base/whatis-ptype-typedefs.exp on 32-bit archs
authorPedro Alves <palves@redhat.com>
Mon, 20 Nov 2017 23:03:17 +0000 (23:03 +0000)
committerPedro Alves <palves@redhat.com>
Mon, 20 Nov 2017 23:03:17 +0000 (23:03 +0000)
The gdb.base/whatis-ptype-typedefs.exp testcase has several tests that
fail on 32-bit architectures.  E.g., on 'x86-64 -m32', I see:

 ...
 FAIL: gdb.base/whatis-ptype-typedefs.exp: lang=c: cast: whatis (float_typedef) v_uchar_array_t_struct_typedef (invalid)
 FAIL: gdb.base/whatis-ptype-typedefs.exp: lang=c: cast: ptype (float_typedef) v_uchar_array_t_struct_typedef (invalid)
 ...

gdb.log:

 (gdb) whatis (float_typedef) v_uchar_array_t_struct_typedef
 type = float_typedef
 (gdb) FAIL: gdb.base/whatis-ptype-typedefs.exp: lang=c: cast: whatis (float_typedef) v_uchar_array_t_struct_typedef (invalid)

As Simon explained [1], the issue boils down to the fact that on
64-bit, this is an invalid cast:

 (gdb) p (float_typedef) v_uchar_array_t_struct_typedef
 Invalid cast.

while on 32 bits it is valid:

 (gdb) p (float_typedef) v_uchar_array_t_struct_typedef
 $1 = 1.16251721e-41

The expression basically tries to cast an array (which decays to a
pointer) to a float.  The cast works on 32 bits because a float and a
pointer are of the same size, and value_cast works in that case:

~~~
   More general than a C cast: accepts any two types of the same length,
   and if ARG2 is an lvalue it can be cast into anything at all.  */
~~~

On 64 bits, they are not the same size, so it ends throwing the
"Invalid cast" error.

The testcase is expecting the invalid cast behavior, thus the FAILs.

A point of these tests was to cover as many code paths in value_cast
as possible, as a sort of documentation of the current behavior:

    # The main idea here is testing all the different paths in the
    # value casting code in GDB (value_cast), making sure typedefs are
    # preserved.
...
    # We try all combinations, even those that don't parse, or are
    # invalid, to catch the case of a regression making them
    # inadvertently valid.  For example, these convertions are
    # invalid:
...

In that spirit, this commit makes the testcase adjust itself depending
on size of floats and pointers, and also test floats of different
sizes.

Passes cleanly on x86-64 GNU/Linux both -m64/-m32.

[1] - https://sourceware.org/ml/gdb-patches/2017-11/msg00382.html

gdb/ChangeLog:
2017-11-20  Pedro Alves  <palves@redhat.com>

* gdb.base/whatis-ptype-typedefs.c (double_typedef)
(long_double_typedef): New typedefs.
Use DEF on double and long double.
* gdb.base/whatis-ptype-typedefs.exp: Add double and long double
cases.
(run_tests): New 'float_ptr_same_size', 'double_ptr_same_size',
and 'long_double_ptr_same_size' locals.  Use them to decide
whether cast from array/function to float is valid/invalid.

gdb/testsuite/ChangeLog
gdb/testsuite/gdb.base/whatis-ptype-typedefs.c
gdb/testsuite/gdb.base/whatis-ptype-typedefs.exp

index 12938e7074260ea84083c0b93a19036a486d407d..fa329b47906a8be0737db967656d848f9c6d86a7 100644 (file)
@@ -1,3 +1,14 @@
+2017-11-20  Pedro Alves  <palves@redhat.com>
+
+       * gdb.base/whatis-ptype-typedefs.c (double_typedef)
+       (long_double_typedef): New typedefs.
+       Use DEF on double and long double.
+       * gdb.base/whatis-ptype-typedefs.exp: Add double and long double
+       cases.
+       (run_tests): New 'float_ptr_same_size', 'double_ptr_same_size',
+       and 'long_double_ptr_same_size' locals.  Use them to decide
+       whether cast from array/function to float is valid/invalid.
+
 2017-11-17  Tom Tromey  <tom@tromey.com>
 
        * gdb.rust/traits.rs: New file.
index 5711a96258349b8d0bd7e47eef6fa665a9cf5446..35c7279c0f30e2f9a5a393bce9632737f773caaa 100644 (file)
@@ -56,6 +56,16 @@ DEF (int);
 typedef float float_typedef;
 DEF (float);
 
+/* Double floats.  */
+
+typedef double double_typedef;
+DEF (double);
+
+/* Long doubles.  */
+
+typedef long double long_double_typedef;
+DEF (long_double);
+
 /* Enums.  */
 
 typedef enum colors {red, green, blue} colors_typedef;
index d333d812384b7d9b700f051371dd60632469280c..ea0ef6ca2ac9ea6c2cbb43acdcd447b9103cf0ae 100644 (file)
@@ -92,6 +92,16 @@ set table {
     {"v_float_typedef"    "float_typedef"    "float"}
     {"v_float_typedef2"   "float_typedef2"   "float"}
 
+    {"double_typedef"     "double"           "double"}
+    {"double_typedef2"    "double_typedef"   "double"}
+    {"v_double_typedef"   "double_typedef"   "double"}
+    {"v_double_typedef2"  "double_typedef2"  "double"}
+
+    {"long_double_typedef"    "long double"           "long double"}
+    {"long_double_typedef2"   "long_double_typedef"   "long double"}
+    {"v_long_double_typedef"  "long_double_typedef"   "long double"}
+    {"v_long_double_typedef2" "long_double_typedef2"  "long double"}
+
     {"colors_typedef"     "(enum )?colors"   "enum colors( : unsigned int)? {red, green, blue}"}
     {"colors_typedef2"    "colors_typedef"   "enum colors( : unsigned int)? {red, green, blue}"}
     {"v_colors_typedef"   "colors_typedef"   "enum colors( : unsigned int)? {red, green, blue}"}
@@ -199,6 +209,22 @@ proc run_tests {lang} {
        }
     }
 
+    # If floats and pointers have the same size on this architecture,
+    # then casting from array/function to float works, because
+    # arrays/functions first decay to pointers, and then GDB's cast is
+    # more general than a C cast and accepts any two types of the same
+    # length.
+    set float_ptr_same_size \
+       [get_integer_valueof "sizeof (float) == sizeof (void *)" -1]
+
+    # Ditto double.
+    set double_ptr_same_size \
+       [get_integer_valueof "sizeof (double) == sizeof (void *)" -1]
+
+    # Ditto long double.
+    set long_double_ptr_same_size \
+       [get_integer_valueof "sizeof (long double) == sizeof (void *)" -1]
+
     # Test converting/casting all variables in the first column of the
     # table to all types (found in the first column of the table).
     # The aggregates are all defined to be the same size so that
@@ -230,7 +256,7 @@ proc run_tests {lang} {
                # regression making them inadvertently valid.  For
                # example, these convertions are invalid:
                #
-               #  float <-> array
+               #  float <-> array   [iff sizeof pointer != sizeof float]
                #  array -> function (not function pointer)
                #  array -> member_ptr
                #
@@ -247,8 +273,15 @@ proc run_tests {lang} {
                    gdb_test "whatis ($to) $from" "syntax error.*" "whatis ($to) $from (syntax)"
                    gdb_test "ptype ($to) $from" "syntax error.*" "ptype ($to) $from (syntax)"
                } elseif {([string match "*float*" $from] && [string match "*array*" $to])
-                         || ([string match "float*" $to] && [string match "*array*" $from])
-                         || ([string match "float*" $to] && [string match "*method" $from])
+                         || (!$float_ptr_same_size
+                             && ([string match "float*" $to] && [string match "*array*" $from]
+                                 || [string match "float*" $to] && [string match "*method" $from]))
+                         || (!$double_ptr_same_size
+                             && ([string match "double*" $to] && [string match "*array*" $from]
+                                 || [string match "double*" $to] && [string match "*method" $from]))
+                         || (!$long_double_ptr_same_size
+                             && ([string match "long_double*" $to] && [string match "*array*" $from]
+                                 || [string match "long_double*" $to] && [string match "*method" $from]))
                          || ([string match "*ftype" $to] && [string match "*array*" $from])
                          || ([string match "*ftype2" $to] && [string match "*array*" $from])
                          || ([string match "*ftype" $to] && [string match "*method" $from])