Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Debuginfo type names: Correctly handle generic arguments in paths #86289

Open
michaelwoerister opened this issue Jun 14, 2021 · 1 comment
Open
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.

Comments

@michaelwoerister
Copy link
Member

Currently paths in stringified type names emitted to debuginfo are generated by simply concatenating the components of corresponding DefPaths. If the type also includes generic arguments these will then just be appended at the end. This works OK as long as all arguments actually belong to the item in question but in cases where some of the arguments actually belong to enclosing items (i.e. further up the path) then this leads undesirable outcomes.

E.g. if we have the following impl

impl<T> Foo<T> {
    fn foo<U>() { 
        let some_closure = || { 
           // ...
        };
    }
}

then we want a concrete instance with T=u32 and U=bool of the closure type to be printed as

<Foo<u32>>::foo::<bool>::{closure#0}

but instead we get something like

<Foo<T>>::foo::{closure#0}<u32, bool> // with #86167 solved
// or 
some::path::{impl#0}::foo::{closure#0}<u32, bool> // without #86167 solved

Concretely we want generic parameters in paths to be

  • replaced with concrete values (if there are concrete values), or
  • erased where the parameter does not matter (e.g. in <Foo<_>>::foo::<_>::SOME_STATIC).
@michaelwoerister michaelwoerister added A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. labels Jun 14, 2021
@michaelwoerister
Copy link
Member Author

Upon closer inspection it turns out that there are some restrictions on what we can implement here at the moment:

  • The only place this problem shows up is when printing function names,
  • but we don't have full control over how function names are printed.

We only explicitly generate the unqualified name of a given function. E.g. for the following function:

mod foo {
    fn bar() {}
}

we only generate the name bar. If the full path foo::bar() is displayed somewhere it is reconstructed either from the function's symbol name (GDB 9.2) or from the DWARF DIE tree structure (GDB 10.2 and CDB). Let's leave aside the symbol name case for now.

When reconstructing the path from the DIE tree we run into the problem that this tree is only a crude approximation of the underlying Rust program because LLVM and debuginfo formats are C++ centric:

  • if bar is an inherent method its parent is the DIE corresponding to the impl's self-type, which includes the self-type's generic arguments:
    struct Foo<T>;
    impl<T> Foo<T> {
      fn bar<U>(&self) {}
    }
    
    let x: Foo<u32> = ...;
    x.bar(false);
    The enclosing scope of this bar instance will be Foo<u32>. Appending all generic arguments to the function's unqualified name will lead to the path Foo<u32>::bar<u32, bool>(). However, we want something like Foo<u32>::bar<bool>() here.
  • if bar is a closure or a trait method the compiler will place it in the "parallel namespace tree" that it generates for things that it cannot represent otherwise. For the trait method case we would end up with a path like {impl#123}::bar<u32, bool>() (where {impl#123} is a namespace) and for the closure case we get a path like bar::{closure#123}<u32, bool> where bar also is a namespace (not a DW_TAG_subprogram DIE).

So where does that leave us? At the moment it does not seem to be possible to implement a really clean solution for this because LLVM/Dwarf/CodeView don't know about impl. What we can do for now is

  • fix the handling of generic arguments for inherent methods (so that parent generics don't get duplicated at the end) and
  • experiment with making closures children of the appropriate DW_TAG_subprogram DIE instead of a namespace.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-debuginfo Area: Debugging information in compiled programs (DWARF, PDB, etc.) T-compiler Relevant to the compiler team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests

1 participant