gnzlbg / cargo-asm

cargo subcommand showing the assembly or llvm-ir generated for Rust code
https://github.com/gnzlbg/cargo-asm
Other
1.17k stars 36 forks source link

Support for opaque types / impl Trait #177

Open agausmann opened 4 years ago

agausmann commented 4 years ago

I'd like to be able to analyze an opaque type, impl Iterator<Item = T>, which I am creating using iterator combinators and does not have a explicit type name because it uses closures.

Here's an example where I try to assign a name to the type using the nightly feature type_alias_impl_trait.

#![feature(type_alias_impl_trait)]

pub struct Foo {/* ... */}

#[derive(Clone)]
pub struct Bar {/* ... */}

pub type Iter = impl Iterator<Item = Bar>;

impl Foo {
    pub fn bar(self) -> Iter {
        // fake impl to define the type of `Iter`
        std::iter::repeat(Bar {/* ... */})
    }
}

I would expect cargo-asm <foo::Iter as std::iter::Iterator>::next to show me the assembly for the named function, but it does not list that function as an option.

agausmann commented 4 years ago

I don't see anything here that would prevent it from loading the function from the build output. I looked one step higher, and found out that the function I'm looking for isn't named in the symbol table.

$ objdump -t target/release/libfoo.rlib
In archive target/release/libfoo.rlib:

foo-1346053a365730c3.foo.es16jqu5-cgu.0.rcgu.o:     file format elf64-x86-64

SYMBOL TABLE:
0000000000000000 l    df *ABS*  0000000000000000 foo.es16jqu5-cgu.0
0000000000000000 l    d  .text._ZN3foo3Foo3bar17h8c343f63e193d4d0E  0000000000000000 .text._ZN3foo3Foo3bar17h8c343f63e193d4d0E
0000000000000000 g     F .text._ZN3foo3Foo3bar17h8c343f63e193d4d0E  0000000000000001 _ZN3foo3Foo3bar17h8c343f63e193d4d0E

objdump: lib.rmeta: file format not recognized
objdump: foo-1346053a365730c3.foo.es16jqu5-cgu.0.rcgu.bc.z: file format not recognized
agausmann commented 4 years ago

Here's a godbolt example, demonstrating:

  1. the opaque type itself (Iter),
  2. a wrapper struct around the explicit type behind the opaque type (Iter2), and
  3. a wrapper struct around the opaque type itself (Iter3).

There doesn't seem to be any code generated for these impl Trait type aliases yet, but the wrapper struct looks like a valid workaround.

agausmann commented 4 years ago

Unfortunately, the code for <Iter3 as std::iter::Iterator>::next disappears when compiling with optimizations (-O),

I ran into problems applying this to my larger use case as well. The wrapper struct method fails to compile because the opaque type is assigned to () for some reason.

error[E0277]: `()` is not an iterator
   --> src/position.rs:374:1
    |
374 | type DirGolemIter = impl Iterator<Item = Move>;
    | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `()` is not an iterator
    |
    = help: the trait `std::iter::Iterator` is not implemented for `()`
    = note: the return type of a function must have a statically known size

It appears that these kinds of type aliases are more unstable than I thought...