rust-lang / rust-lang/rust

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

Open
#144,525 4 comments 1 reaction 0 assignees View on GitHub

Nobody has claimed this yet.

A-debuginfo A-name-mangling C-bug T-compiler
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

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>

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Run the supplied generic-method reproduction under rust-gdb, then inspect rust-lang.c, especially rust_structop::evaluate_funcall and its lookup_symbol call. Compare the symbol names shown by info functions with the method name constructed for lookup. Done means method calls on generic impl blocks resolve in rust-gdb without breaking existing specialized-method lookups.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
devtools
Issue type
Bug
Difficulty
4/5
Estimated time
3-5 days
Activity status
Stale
Clarity
Mostly clear
Newbie friendliness
48/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.