Skip to content

Rust appears to create (duplicate?) vtables at runtime that could have been emitted at compile-time. #8591

Closed
@Thiez

Description

@Thiez

The code below outputs ((6340760, 140201758297392), (6340840, 140201758297424), (6340856, 140201758297472), (6340872, 140201758297504)) (exact numbers may vary). The important part is that the vtables seem to get newly created for ~1 and ~2 (and also @1 and @2) even though they could easily use the same vtables.

use std::cast::transmute;
trait Foo {
  fn foo(&self) {}
}
impl Foo for uint {}
impl Foo for int {}
unsafe {
  (transmute::<~Foo, (uint,uint)>(~1i as ~Foo),
   transmute::<@Foo, (uint,uint)>(@1i as @Foo),
   transmute::<~Foo, (uint,uint)>(~2i as ~Foo),
   transmute::<@Foo, (uint,uint)>(@2i as @Foo))
}

The code was fed to rusti, original below (thanks to dbaupp):

13:55 < dbaupp> rusti: use std::cast::transmute; trait Foo { fn foo(&self) {} } impl Foo for uint {} impl Foo for int {} unsafe {(transmute::<~Foo, (uint,uint)>(~1i as ~Foo),transmute::<@Foo, (uint,uint)>(@1i as @Foo),transmute::<~Foo, (uint,uint)>(~2i as ~Foo),transmute::<@Foo, (uint,uint)>(@2i as @Foo))}
13:55 -rusti:#rust- ((6340760, 140201758297392), (6340840, 140201758297424), (6340856, 140201758297472), (6340872, 140201758297504))

Swapping vtables appears to work just fine, even between ~Trait and &Trait (but not between ~Trait and @trait):

use std::cast::transmute;
trait Foo{
  fn foo(&mut self);
  fn bar(&self)->int;
}
impl Foo for int{
  fn foo(&mut self) {
    *self=*self+1
  }
  fn bar(&self)->int{
    *self
  }
};
unsafe{
  let (a1,a2) = transmute::<~Foo,(uint,uint)>(~1 as ~Foo);
  let (b1,b2) = transmute::<&mut Foo,(uint,uint)>(&mut 2 as &mut Foo);
  let mut a = transmute::<(uint,uint),~Foo>((b1,a2));
  let b = transmute::<(uint,uint),&mut Foo>((a1,b2));
  a.foo();b.foo();
  (a.bar(),b.bar() )
}

Outputs (2,3) in rusti.

14:24 < Thiez> rusti: use std::cast::transmute; trait Foo{fn foo(&mut self);fn bar(&self)->int;} impl Foo for int{fn foo(&mut self){*self=*self+1}fn bar(&self)->int{*self}}; unsafe{ let
               (a1,a2)=transmute::<~Foo,(uint,uint)>(~1 as ~Foo); let (b1,b2)=transmute::<&mut Foo,(uint,uint)>(&mut 2 as &mut Foo); let mut a=transmute::<(uint,uint),~Foo>((b1,a2));let b =
               transmute::<(uint,uint),&mut Foo>((a1,b2)); a.foo();b.foo();(a.bar(),b.bar()) }
14:24 -rusti:#rust- (2, 3)

It seems to me we should generate the vtables at compile time.

Metadata

Metadata

Assignees

No one assigned

    Labels

    A-codegenArea: Code generationA-trait-systemArea: Trait systemA-type-systemArea: Type systemE-needs-testCall for participation: An issue has been fixed and does not reproduce, but no test has been added.

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions