Skip to content

rust-gdb can't call methods defined in impl blocks with generics #144525

@apodolsk

Description

@apodolsk

Consider:

use std::fmt::Debug;

#[derive(Default)]
struct Plain {
    a: usize
}

impl Plain {
    fn f(&self) {
        dbg!(self.a);
    }
}

#[derive(Default)]
struct Generic<A: Default> {
    a: A
}

impl<A: Debug + Default> Generic<A> {
    fn f(&self) {
        dbg!(&self.a);
    }

    fn f_with_its_own_generics<B: Debug>(&self, b: &B) {
        dbg!(b);
    }
}

impl Generic<usize> {
    fn f_specialized(&self) {
        dbg!(self.a);
    }
}

impl<A: Debug> Generic<Option<A>> {
    fn f_different_generics(&self) {
        dbg!(&self.a);
    }
}

fn main() {
    let p = Plain::default();
    let g1 = Generic::<usize>::default();
    let g2 = Generic::<Option<usize>>::default();

    unsafe { std::arch::asm!("int3"); }

    p.f();
    g1.f();
    g1.f_specialized();
    g1.f_with_its_own_generics(&"hello");

    g2.f();
    g2.f_different_generics();
    g2.f_with_its_own_generics(&"hello");
}

rust-gdb against a debug build of the above can evaluate p.f() and g1.f_specialized(), but not g1.f(), despite that function being present enough in the binary to break on:

Program received signal SIGTRAP, Trace/breakpoint trap.
gdb_generics_repro::main () at src/main.rs:48
48	    p.f();
(gdb) p p.f()
[src/main.rs:10:9] self.a = 0
$3 = ()
(gdb) p g1.f_specialized()
[src/main.rs:31:9] self.a = 0
$4 = ()
(gdb) p g1.f()
Could not find function named 'gdb_generics_repro::Generic<usize>::f'
(gdb) i functions .*Generic.*f
All functions matching regular expression ".*Generic.*f":

File src/main.rs:
20:	static fn gdb_generics_repro::Generic<core::option::Option<usize>>::f<core::option::Option<usize>>(*mut gdb_generics_repro::Generic<core::option::Option<usize>>);
36:	static fn gdb_generics_repro::Generic<core::option::Option<usize>>::f_different_generics<usize>(*mut gdb_generics_repro::Generic<core::option::Option<usize>>);
24:	static fn gdb_generics_repro::Generic<core::option::Option<usize>>::f_with_its_own_generics<core::option::Option<usize>, &str>(*mut gdb_generics_repro::Generic<core::option::Option<usize>>, *mut &str);
20:	static fn gdb_generics_repro::Generic<usize>::f<usize>(*mut gdb_generics_repro::Generic<usize>);
30:	static fn gdb_generics_repro::Generic<usize>::f_specialized(*mut gdb_generics_repro::Generic<usize>);
24:	static fn gdb_generics_repro::Generic<usize>::f_with_its_own_generics<usize, &str>(*mut gdb_generics_repro::Generic<usize>, *mut &str);
(gdb) b gdb_generics_repro::Generic<usize>::f<usize>
Breakpoint 4 at 0x555555569d39: file src/main.rs, line 21.

The issue is with these trailing generics after method function names, e.g. the second <usize> in gdb_generics_repro::Generic<usize>::f<usize>. They apparently correspond to the generic params of the function's containing impl, and are printed as if they're generic params of the function even for functions which aren't actually generic.

Besides being necessary for b, I see that these extra generics are necessary for lookup_symbol triggered from a python extension. But the method lookup logic in rust-lang.c seems to omit them:

value *
rust_structop::evaluate_funcall (struct type *expect_type,
				 struct expression *exp,
				 enum noside noside,
				 const std::vector<operation_up> &ops)
{
  std::vector<struct value *> args (ops.size () + 1);

  /* Evaluate the argument to STRUCTOP_STRUCT, then find its
     type in order to look up the method.  */
  args[0] = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
  /* We don't yet implement real Deref semantics.  */
  while (args[0]->type ()->code () == TYPE_CODE_PTR)
    args[0] = value_ind (args[0]);

  struct type *type = args[0]->type ();
  if ((type->code () != TYPE_CODE_STRUCT
       && type->code () != TYPE_CODE_UNION
       && type->code () != TYPE_CODE_ENUM)
      || rust_tuple_type_p (type))
    error (_("Method calls only supported on struct or enum types"));
  if (type->name () == NULL)
    error (_("Method call on nameless type"));

  std::string name = (std::string (type->name ()) + "::"
		      + std::get<1> (m_storage));

  const struct block *block = get_selected_block (0);
  struct block_symbol sym = lookup_symbol (name.c_str (), block,
					   SEARCH_FUNCTION_DOMAIN,
					   nullptr);

Generics are pretty common, so I suspect lots of people are hitting this and thinking rust-gdb just doesn't support method calls.

Is it maybe just a bug that impl generics started getting included in method names at some point? I can't see what ambiguity they'd be resolving, given that the generics of the underlying struct are also part of the symbol.

Note that the impl generics part of the name can differ from the struct generics part, as with f_different_generics() above.

cc: @tromey

Meta

rustc --version --verbose:

rustc 1.89.0-nightly (59aa1e873 2025-06-03)
binary: rustc
commit-hash: 59aa1e873028948faaf8b97e5e02d4db340ad7b1
commit-date: 2025-06-03
host: x86_64-unknown-linux-gnu
release: 1.89.0-nightly
LLVM version: 20.1.5
~/code/scrap/rust/gdb_generics_repro/src: gdb --version
GNU gdb (GDB) 16.3
Backtrace

<backtrace>

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-debuginfoArea: Debugging information in compiled programs (DWARF, PDB, etc.)A-name-manglingArea: name mangling / decorationC-bugCategory: This is a bug.needs-triageThis issue may need triage. Remove it if it has been sufficiently triaged.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions