Fix "b f(std::string)" when current language is C
authorPedro Alves <pedro@palves.net>
Fri, 29 Apr 2022 22:21:18 +0000 (23:21 +0100)
committerPedro Alves <pedro@palves.net>
Tue, 10 May 2022 13:16:21 +0000 (14:16 +0100)
If you try to set a breakpoint at a function such as "b
f(std::string)", and the current language is C, the breakpoint fails
to be set, like so:

  (gdb) set language c
  break f(std::string)
  Function "f(std::string)" not defined.
  Make breakpoint pending on future shared library load? (y or [n]) n
  (gdb)

The problem is that the code in GDB that expands the std::string
typedef hits this in c-typeprint.c:

      /* If we have "typedef struct foo {. . .} bar;" do we want to
 print it as "struct foo" or as "bar"?  Pick the latter for
 C++, because C++ folk tend to expect things like "class5
 *foo" rather than "struct class5 *foo".  We rather
 arbitrarily choose to make language_minimal work in a C-like
 way. */
      if (language == language_c || language == language_minimal)
{
  if (type->code () == TYPE_CODE_UNION)
    gdb_printf (stream, "union ");
  else if (type->code () == TYPE_CODE_STRUCT)
    {
      if (type->is_declared_class ())
gdb_printf (stream, "class ");
      else
gdb_printf (stream, "struct ");
    }
  else if (type->code () == TYPE_CODE_ENUM)
    gdb_printf (stream, "enum ");
}

I.e., std::string is expanded to "class std::..." instead of just
"std::...", and then the "f(class std::..." symbol doesn't exist.

Fix this by making cp-support.c:inspect_type print the expanded
typedef type using the language of the symbol whose type we're
expanding the typedefs for -- in the example in question, the
"std::string" typedef symbol, which is a C++ symbol.

Use type_print_raw_options as it seems to me that in this scenario we
always want raw types, to match the real symbol names.

Adjust the gdb.cp/break-f-std-string.exp testcase to try setting a
breakpoint at "f(std::string)" in both C and C++.

Change-Id: Ib54fab4cf0fd307bfd55bf1dd5056830096a653b

gdb/cp-support.c
gdb/testsuite/gdb.cp/break-f-std-string.exp

index 71c14635e3882e4bac573915774a914769b6f8df..807c944a97c46f98de22d65f4e9562ce14534152 100644 (file)
@@ -41,6 +41,7 @@
 #include <atomic>
 #include "event-top.h"
 #include "run-on-main-thread.h"
+#include "typeprint.h"
 
 #define d_left(dc) (dc)->u.s_binary.left
 #define d_right(dc) (dc)->u.s_binary.right
@@ -229,7 +230,14 @@ inspect_type (struct demangle_parse_info *info,
          string_file buf;
          try
            {
-             type_print (type, "", &buf, -1);
+             /* Avoid using the current language.  If the language is
+                C, and TYPE is a struct/class, the printed type is
+                prefixed with "struct " or "class ", which we don't
+                want when we're expanding a C++ typedef.  Print using
+                the type symbol's language to expand a C++ typedef
+                the C++ way even if the current language is C.  */
+             const language_defn *lang = language_def (sym->language ());
+             lang->print_type (type, "", &buf, -1, 0, &type_print_raw_options);
            }
          /* If type_print threw an exception, there is little point
             in continuing, so just bow out gracefully.  */
index 0869912bb29fb3b2027ba574931e68474a8f2128..e222bae8ab3412e283331bb0d9d1817fc1d597d3 100644 (file)
@@ -93,10 +93,17 @@ proc test {cxx11_abi} {
        }
     }
 
-    gdb_test "break f($type)" "$srcfile, line $::decimal\\."
+    # GDB should be able to expand the std::string typedef in the
+    # function prototype using C++ logic even if the current language
+    # is C.
+    foreach_with_prefix lang {"c" "c++"} {
+       gdb_test_no_output "set language $lang"
 
-    if { $realtype != "" } {
-       gdb_test "break f($realtype)" "$srcfile, line $::decimal\\."
+       gdb_test "break f($type)" "$srcfile, line $::decimal\\."
+
+       if { $realtype != "" } {
+           gdb_test "break f($realtype)" "$srcfile, line $::decimal\\."
+       }
     }
 }