Skip to content

Codegen errors creduced from stylo #638

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

Closed
fitzgen opened this issue Apr 17, 2017 · 5 comments
Closed

Codegen errors creduced from stylo #638

fitzgen opened this issue Apr 17, 2017 · 5 comments

Comments

@fitzgen
Copy link
Member

fitzgen commented Apr 17, 2017

Input C/C++ Header

template <class> class RefPtr {};
class b;
class c;
class B {
  c *d;
};
class e {
  typedef b a;
};
class f {
public:
  f(B);
};
template <typename T> class i {
  typedef T g;
  RefPtr<g> h;
};
class l {
  i<int> j;
};
class c {
  l k;
};
class b : f {};
e Servo_Element_GetSnapshot();

Bindgen Invokation

Something like:

$BINDGEN
    --raw-line "#[derive(Copy)] pub struct RefPtr<T>(T);" \
    --whitelist-function "Servo_.*" \
    $HEADER \
    -- \
    --std=c++14

Actual Results

/* automatically generated by rust-bindgen */

#[derive(Copy)] pub struct RefPtr<T>(T);

#[repr(C)]
#[derive(Debug, Copy)]
pub struct b {
    pub _address: u8,
}
#[test]
fn bindgen_test_layout_b() {
    assert_eq!(::std::mem::size_of::<b>() , 1usize , concat ! (
               "Size of: " , stringify ! ( b ) ));
    assert_eq! (::std::mem::align_of::<b>() , 1usize , concat ! (
                "Alignment of " , stringify ! ( b ) ));
}
impl Clone for b {
    fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct c {
    pub k: l,
}
#[test]
fn bindgen_test_layout_c() {
    assert_eq!(::std::mem::size_of::<c>() , 1usize , concat ! (
               "Size of: " , stringify ! ( c ) ));
    assert_eq! (::std::mem::align_of::<c>() , 1usize , concat ! (
                "Alignment of " , stringify ! ( c ) ));
    assert_eq! (unsafe { & ( * ( 0 as * const c ) ) . k as * const _ as usize
                } , 0usize , concat ! (
                "Alignment of field: " , stringify ! ( c ) , "::" , stringify
                ! ( k ) ));
}
impl Clone for c {
    fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct B {
    pub d: *mut c,
}
#[test]
fn bindgen_test_layout_B() {
    assert_eq!(::std::mem::size_of::<B>() , 8usize , concat ! (
               "Size of: " , stringify ! ( B ) ));
    assert_eq! (::std::mem::align_of::<B>() , 8usize , concat ! (
                "Alignment of " , stringify ! ( B ) ));
    assert_eq! (unsafe { & ( * ( 0 as * const B ) ) . d as * const _ as usize
                } , 0usize , concat ! (
                "Alignment of field: " , stringify ! ( B ) , "::" , stringify
                ! ( d ) ));
}
impl Clone for B {
    fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct e {
    pub _address: u8,
}
pub type e_a = b;
#[test]
fn bindgen_test_layout_e() {
    assert_eq!(::std::mem::size_of::<e>() , 1usize , concat ! (
               "Size of: " , stringify ! ( e ) ));
    assert_eq! (::std::mem::align_of::<e>() , 1usize , concat ! (
                "Alignment of " , stringify ! ( e ) ));
}
impl Clone for e {
    fn clone(&self) -> Self { *self }
}
#[repr(C)]
#[derive(Debug, Copy)]
pub struct f {
    pub _address: u8,
}
#[test]
fn bindgen_test_layout_f() {
    assert_eq!(::std::mem::size_of::<f>() , 1usize , concat ! (
               "Size of: " , stringify ! ( f ) ));
    assert_eq! (::std::mem::align_of::<f>() , 1usize , concat ! (
                "Alignment of " , stringify ! ( f ) ));
}
extern "C" {
    #[link_name = "_ZN1fC1E1B"]
    pub fn f_f(this: *mut f, arg1: B);
}
impl Clone for f {
    fn clone(&self) -> Self { *self }
}
impl f {
    #[inline]
    pub unsafe fn new(arg1: B) -> Self {
        let mut __bindgen_tmp = ::std::mem::uninitialized();
        f_f(&mut __bindgen_tmp, arg1);
        __bindgen_tmp
    }
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct i {
    pub h: RefPtr<i_g<T>>,
}
pub type i_g<T> = T;
#[repr(C)]
#[derive(Debug, Copy)]
pub struct l {
    pub j: i,
}
#[test]
fn bindgen_test_layout_l() {
    assert_eq!(::std::mem::size_of::<l>() , 1usize , concat ! (
               "Size of: " , stringify ! ( l ) ));
    assert_eq! (::std::mem::align_of::<l>() , 1usize , concat ! (
                "Alignment of " , stringify ! ( l ) ));
    assert_eq! (unsafe { & ( * ( 0 as * const l ) ) . j as * const _ as usize
                } , 0usize , concat ! (
                "Alignment of field: " , stringify ! ( l ) , "::" , stringify
                ! ( j ) ));
}
impl Clone for l {
    fn clone(&self) -> Self { *self }
}
extern "C" {
    #[link_name = "_Z25Servo_Element_GetSnapshotv"]
    pub fn Servo_Element_GetSnapshot() -> e;
}

Which then results in compilation errors:

$ rustc --test --crate-type lib stylo_bindings.rs 
error[E0412]: cannot find type `T` in this scope
   --> stylo_bindings.rs:104:23
    |
104 |     pub h: RefPtr<i_g<T>>,
    |                       ^ did you mean `B`?

error[E0412]: cannot find type `T` in this scope
   --> stylo_bindings.rs:104:23
    |
104 |     pub h: RefPtr<i_g<T>>,
    |                       ^ did you mean `B`?

error[E0204]: the trait `Copy` may not be implemented for this type
   --> stylo_bindings.rs:102:17
    |
102 | #[derive(Debug, Copy, Clone)]
    |                 ^^^^
103 | pub struct i {
104 |     pub h: RefPtr<i_g<T>>,
    |     --------------------- this field does not implement `Copy`

error: aborting due to previous error

cc @emilio

@fitzgen
Copy link
Member Author

fitzgen commented Apr 17, 2017

More reduced, and with names to make things make sense:

// bindgen-flags: -- -std=c++14

template <class T>
class RefPtr {
    T use_of_t;
};

template <typename U>
class UsesRefPtrWithAliasedTypeParam {
    typedef U TypedefU;
    RefPtr<TypedefU> member;
};

@fitzgen
Copy link
Member Author

fitzgen commented Apr 17, 2017

Emitted bindings:

/* automatically generated by rust-bindgen */

#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct RefPtr<T> {
    pub use_of_t: T,
}
#[repr(C)]
#[derive(Debug, Copy, Clone)]
pub struct UsesRefPtrWithAliasedTypeParam {
    pub member: RefPtr<UsesRefPtrWithAliasedTypeParam_TypedefU<U>>,
}
pub type UsesRefPtrWithAliasedTypeParam_TypedefU<U> = U;

IR graph:

ir

We're failing to emit a type alias for the typedef, but it looks like we have everything we need in the IR... Not 100% sure what's up.

@fitzgen
Copy link
Member Author

fitzgen commented Apr 17, 2017

Ahhhh I think this is a bug in how we reconstruct template instantiations when clang won't give us the info we need.

@fitzgen
Copy link
Member Author

fitzgen commented Apr 17, 2017

Ahhhh I think this is a bug in how we reconstruct template instantiations when clang won't give us the info we need.

Wait, wrong again. We have the correct IR, but we end up generating a generic instantiation from the alias instead of just using it...

    pub member: RefPtr<UsesRefPtrWithAliasedTypeParam_TypedefU<U>>,

Instead of

    pub member: RefPtr<UsesRefPtrWithAliasedTypeParam_TypedefU>,

And generating the appropriate type alias.

@fitzgen
Copy link
Member Author

fitzgen commented Apr 17, 2017

Ok, I have a fix incoming.

fitzgen added a commit to fitzgen/rust-bindgen that referenced this issue Apr 17, 2017
In stylo bindings generation, we were hitting bugs where the analysis saw a
template type parameter behind a type ref to a type alias, and this was then
used as an argument to a template instantiation. Because of the indirection, the
analysis got confused and ignored the template argument because it was "not" a
named template type, and therefore we didn't care about its usage.

This commit makes sure that we keep resolving through type references and
aliases to find the inner named template type parameter to add to the current
item's usage set.

Fixes rust-lang#638.
Kowasaki pushed a commit to Kowasaki/rust-bindgen that referenced this issue May 2, 2017
In stylo bindings generation, we were hitting bugs where the analysis saw a
template type parameter behind a type ref to a type alias, and this was then
used as an argument to a template instantiation. Because of the indirection, the
analysis got confused and ignored the template argument because it was "not" a
named template type, and therefore we didn't care about its usage.

This commit makes sure that we keep resolving through type references and
aliases to find the inner named template type parameter to add to the current
item's usage set.

Fixes rust-lang#638.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

1 participant