<p dir="auto">The code below outputs <code class="notranslate">((6340760, 140201758297392), (6340840, 140201758297424), (6340856, 140201758297472), (6340872, 140201758297504))</code> (exact numbers may vary). The important part is that the vtables seem to get newly created for ~1 and ~2 (and also <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/1/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/1">@1</a> and <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/2/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/2">@2</a>) even though they could easily use the same vtables.</p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="use std::cast::transmute;
trait Foo {
  fn foo(&amp;self) {}
}
impl Foo for uint {}
impl Foo for int {}
unsafe {
  (transmute::&lt;~Foo, (uint,uint)&gt;(~1i as ~Foo),
   transmute::&lt;@Foo, (uint,uint)&gt;(@1i as @Foo),
   transmute::&lt;~Foo, (uint,uint)&gt;(~2i as ~Foo),
   transmute::&lt;@Foo, (uint,uint)&gt;(@2i as @Foo))
}"><pre class="notranslate"><span class="pl-k">use</span> std<span class="pl-kos">::</span>cast<span class="pl-kos">::</span>transmute<span class="pl-kos">;</span>
<span class="pl-k">trait</span> <span class="pl-smi">Foo</span> <span class="pl-kos">{</span>
  <span class="pl-k">fn</span> <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-c1">&amp;</span><span class="pl-smi">self</span><span class="pl-kos">)</span> <span class="pl-kos">{</span><span class="pl-kos">}</span>
<span class="pl-kos">}</span>
<span class="pl-k">impl</span> <span class="pl-smi">Foo</span> <span class="pl-k">for</span> <span class="pl-smi">uint</span> <span class="pl-kos">{</span><span class="pl-kos">}</span>
<span class="pl-k">impl</span> <span class="pl-smi">Foo</span> <span class="pl-k">for</span> <span class="pl-smi">int</span> <span class="pl-kos">{</span><span class="pl-kos">}</span>
<span class="pl-k">unsafe</span> <span class="pl-kos">{</span>
  <span class="pl-kos">(</span><span class="pl-en">transmute</span><span class="pl-kos">::</span><span class="pl-kos">&lt;</span>~<span class="pl-smi">Foo</span><span class="pl-kos">,</span> <span class="pl-kos">(</span><span class="pl-smi">uint</span><span class="pl-kos">,</span><span class="pl-smi">uint</span><span class="pl-kos">)</span><span class="pl-kos">&gt;</span><span class="pl-kos">(</span>~<span class="pl-c1">1</span>i <span class="pl-k">as</span> ~<span class="pl-smi">Foo</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
   <span class="pl-en">transmute</span><span class="pl-kos">::</span><span class="pl-kos">&lt;</span>@<span class="pl-smi">Foo</span><span class="pl-kos">,</span> <span class="pl-kos">(</span><span class="pl-smi">uint</span><span class="pl-kos">,</span><span class="pl-smi">uint</span><span class="pl-kos">)</span><span class="pl-kos">&gt;</span><span class="pl-kos">(</span>@<span class="pl-c1">1</span>i <span class="pl-k">as</span> @<span class="pl-smi">Foo</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
   <span class="pl-en">transmute</span><span class="pl-kos">::</span><span class="pl-kos">&lt;</span>~<span class="pl-smi">Foo</span><span class="pl-kos">,</span> <span class="pl-kos">(</span><span class="pl-smi">uint</span><span class="pl-kos">,</span><span class="pl-smi">uint</span><span class="pl-kos">)</span><span class="pl-kos">&gt;</span><span class="pl-kos">(</span>~<span class="pl-c1">2</span>i <span class="pl-k">as</span> ~<span class="pl-smi">Foo</span><span class="pl-kos">)</span><span class="pl-kos">,</span>
   <span class="pl-en">transmute</span><span class="pl-kos">::</span><span class="pl-kos">&lt;</span>@<span class="pl-smi">Foo</span><span class="pl-kos">,</span> <span class="pl-kos">(</span><span class="pl-smi">uint</span><span class="pl-kos">,</span><span class="pl-smi">uint</span><span class="pl-kos">)</span><span class="pl-kos">&gt;</span><span class="pl-kos">(</span>@<span class="pl-c1">2</span>i <span class="pl-k">as</span> @<span class="pl-smi">Foo</span><span class="pl-kos">)</span><span class="pl-kos">)</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">The code was fed to rusti, original below (thanks to dbaupp):</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="13:55 &lt; dbaupp&gt; rusti: use std::cast::transmute; trait Foo { fn foo(&amp;self) {} } impl Foo for uint {} impl Foo for int {} unsafe {(transmute::&lt;~Foo, (uint,uint)&gt;(~1i as ~Foo),transmute::&lt;@Foo, (uint,uint)&gt;(@1i as @Foo),transmute::&lt;~Foo, (uint,uint)&gt;(~2i as ~Foo),transmute::&lt;@Foo, (uint,uint)&gt;(@2i as @Foo))}
13:55 -rusti:#rust- ((6340760, 140201758297392), (6340840, 140201758297424), (6340856, 140201758297472), (6340872, 140201758297504))"><pre class="notranslate"><code class="notranslate">13:55 &lt; dbaupp&gt; rusti: use std::cast::transmute; trait Foo { fn foo(&amp;self) {} } impl Foo for uint {} impl Foo for int {} unsafe {(transmute::&lt;~Foo, (uint,uint)&gt;(~1i as ~Foo),transmute::&lt;@Foo, (uint,uint)&gt;(@1i as @Foo),transmute::&lt;~Foo, (uint,uint)&gt;(~2i as ~Foo),transmute::&lt;@Foo, (uint,uint)&gt;(@2i as @Foo))}
13:55 -rusti:#rust- ((6340760, 140201758297392), (6340840, 140201758297424), (6340856, 140201758297472), (6340872, 140201758297504))
</code></pre></div>
<p dir="auto">Swapping vtables appears to work just fine, even between ~Trait and &amp;Trait (but not between ~Trait and <a class="user-mention notranslate" data-hovercard-type="organization" data-hovercard-url="/orgs/trait/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/trait">@trait</a>):</p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="use std::cast::transmute;
trait Foo{
  fn foo(&amp;mut self);
  fn bar(&amp;self)-&gt;int;
}
impl Foo for int{
  fn foo(&amp;mut self) {
    *self=*self+1
  }
  fn bar(&amp;self)-&gt;int{
    *self
  }
};
unsafe{
  let (a1,a2) = transmute::&lt;~Foo,(uint,uint)&gt;(~1 as ~Foo);
  let (b1,b2) = transmute::&lt;&amp;mut Foo,(uint,uint)&gt;(&amp;mut 2 as &amp;mut Foo);
  let mut a = transmute::&lt;(uint,uint),~Foo&gt;((b1,a2));
  let b = transmute::&lt;(uint,uint),&amp;mut Foo&gt;((a1,b2));
  a.foo();b.foo();
  (a.bar(),b.bar() )
}"><pre class="notranslate"><span class="pl-k">use</span> std<span class="pl-kos">::</span>cast<span class="pl-kos">::</span>transmute<span class="pl-kos">;</span>
<span class="pl-k">trait</span> <span class="pl-smi">Foo</span><span class="pl-kos">{</span>
  <span class="pl-k">fn</span> <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-c1">&amp;</span><span class="pl-k">mut</span> <span class="pl-smi">self</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">fn</span> <span class="pl-en">bar</span><span class="pl-kos">(</span><span class="pl-c1">&amp;</span><span class="pl-smi">self</span><span class="pl-kos">)</span>-&gt;<span class="pl-smi">int</span><span class="pl-kos">;</span>
<span class="pl-kos">}</span>
<span class="pl-k">impl</span> <span class="pl-smi">Foo</span> <span class="pl-k">for</span> <span class="pl-smi">int</span><span class="pl-kos">{</span>
  <span class="pl-k">fn</span> <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-c1">&amp;</span><span class="pl-k">mut</span> <span class="pl-smi">self</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
    <span class="pl-c1">*</span><span class="pl-smi">self</span>=<span class="pl-c1">*</span><span class="pl-smi">self</span>+<span class="pl-c1">1</span>
  <span class="pl-kos">}</span>
  <span class="pl-k">fn</span> <span class="pl-en">bar</span><span class="pl-kos">(</span><span class="pl-c1">&amp;</span><span class="pl-smi">self</span><span class="pl-kos">)</span>-&gt;<span class="pl-smi">int</span><span class="pl-kos">{</span>
    <span class="pl-c1">*</span><span class="pl-smi">self</span>
  <span class="pl-kos">}</span>
<span class="pl-kos">}</span><span class="pl-kos">;</span>
<span class="pl-k">unsafe</span><span class="pl-kos">{</span>
  <span class="pl-k">let</span> <span class="pl-kos">(</span>a1<span class="pl-kos">,</span>a2<span class="pl-kos">)</span> = <span class="pl-en">transmute</span><span class="pl-kos">::</span><span class="pl-kos">&lt;</span>~<span class="pl-smi">Foo</span><span class="pl-kos">,</span><span class="pl-kos">(</span><span class="pl-smi">uint</span><span class="pl-kos">,</span><span class="pl-smi">uint</span><span class="pl-kos">)</span><span class="pl-kos">&gt;</span><span class="pl-kos">(</span>~<span class="pl-c1">1</span> <span class="pl-k">as</span> ~<span class="pl-smi">Foo</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">let</span> <span class="pl-kos">(</span>b1<span class="pl-kos">,</span>b2<span class="pl-kos">)</span> = <span class="pl-en">transmute</span><span class="pl-kos">::</span><span class="pl-kos">&lt;</span><span class="pl-c1">&amp;</span><span class="pl-k">mut</span> <span class="pl-smi">Foo</span><span class="pl-kos">,</span><span class="pl-kos">(</span><span class="pl-smi">uint</span><span class="pl-kos">,</span><span class="pl-smi">uint</span><span class="pl-kos">)</span><span class="pl-kos">&gt;</span><span class="pl-kos">(</span><span class="pl-c1">&amp;</span><span class="pl-k">mut</span> <span class="pl-c1">2</span> <span class="pl-k">as</span> <span class="pl-c1">&amp;</span><span class="pl-k">mut</span> <span class="pl-smi">Foo</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">let</span> <span class="pl-k">mut</span> a = <span class="pl-en">transmute</span><span class="pl-kos">::</span><span class="pl-kos">&lt;</span><span class="pl-kos">(</span><span class="pl-smi">uint</span><span class="pl-kos">,</span><span class="pl-smi">uint</span><span class="pl-kos">)</span><span class="pl-kos">,</span>~<span class="pl-smi">Foo</span><span class="pl-kos">&gt;</span><span class="pl-kos">(</span><span class="pl-kos">(</span>b1<span class="pl-kos">,</span>a2<span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-k">let</span> b = <span class="pl-en">transmute</span><span class="pl-kos">::</span><span class="pl-kos">&lt;</span><span class="pl-kos">(</span><span class="pl-smi">uint</span><span class="pl-kos">,</span><span class="pl-smi">uint</span><span class="pl-kos">)</span><span class="pl-kos">,</span><span class="pl-c1">&amp;</span><span class="pl-k">mut</span> <span class="pl-smi">Foo</span><span class="pl-kos">&gt;</span><span class="pl-kos">(</span><span class="pl-kos">(</span>a1<span class="pl-kos">,</span>b2<span class="pl-kos">)</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  a<span class="pl-kos">.</span><span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>b<span class="pl-kos">.</span><span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
  <span class="pl-kos">(</span>a<span class="pl-kos">.</span><span class="pl-en">bar</span><span class="pl-kos">(</span><span class="pl-kos">)</span><span class="pl-kos">,</span>b<span class="pl-kos">.</span><span class="pl-en">bar</span><span class="pl-kos">(</span><span class="pl-kos">)</span> <span class="pl-kos">)</span>
<span class="pl-kos">}</span></pre></div>
<p dir="auto">Outputs (2,3) in rusti.</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="14:24 &lt; Thiez&gt; rusti: use std::cast::transmute; trait Foo{fn foo(&amp;mut self);fn bar(&amp;self)-&gt;int;} impl Foo for int{fn foo(&amp;mut self){*self=*self+1}fn bar(&amp;self)-&gt;int{*self}}; unsafe{ let
               (a1,a2)=transmute::&lt;~Foo,(uint,uint)&gt;(~1 as ~Foo); let (b1,b2)=transmute::&lt;&amp;mut Foo,(uint,uint)&gt;(&amp;mut 2 as &amp;mut Foo); let mut a=transmute::&lt;(uint,uint),~Foo&gt;((b1,a2));let b =
               transmute::&lt;(uint,uint),&amp;mut Foo&gt;((a1,b2)); a.foo();b.foo();(a.bar(),b.bar()) }
14:24 -rusti:#rust- (2, 3)"><pre class="notranslate"><code class="notranslate">14:24 &lt; Thiez&gt; rusti: use std::cast::transmute; trait Foo{fn foo(&amp;mut self);fn bar(&amp;self)-&gt;int;} impl Foo for int{fn foo(&amp;mut self){*self=*self+1}fn bar(&amp;self)-&gt;int{*self}}; unsafe{ let
               (a1,a2)=transmute::&lt;~Foo,(uint,uint)&gt;(~1 as ~Foo); let (b1,b2)=transmute::&lt;&amp;mut Foo,(uint,uint)&gt;(&amp;mut 2 as &amp;mut Foo); let mut a=transmute::&lt;(uint,uint),~Foo&gt;((b1,a2));let b =
               transmute::&lt;(uint,uint),&amp;mut Foo&gt;((a1,b2)); a.foo();b.foo();(a.bar(),b.bar()) }
14:24 -rusti:#rust- (2, 3)
</code></pre></div>
<p dir="auto">It seems to me we should generate the vtables at compile time.</p>
<p dir="auto">I'd marked a test case with those two attributes, intended to remove the second one later, but the compiler didn't bother with the second one to begin with. This caused a known-buggy test case to run anyway and wedge the build bots on all but windows.</p>
<p dir="auto">I would have liked to have seen something like <code class="notranslate">warning: duplicate </code>ignore<code class="notranslate"> attribute; ignoring the latter</code></p>