<p dir="auto">In this example</p>
<div class="snippet-clipboard-content notranslate position-relative overflow-auto" data-snippet-clipboard-copy-content="trait Check: std::marker::MarkerTrait {
    fn check();
}
impl Check for u8 {
    fn check() { println!(&quot;u8&quot;); }
}
impl Check for u16 {
    fn check() { println!(&quot;u16&quot;); }
}

fn f&lt;T: Check&gt;() {
    T::check();
}



fn main() {
    fn same_type&lt;T&gt;(_: T, _: T) {}
    same_type(f::&lt;u8&gt;, f::&lt;u16&gt;);
    println!(&quot;{} {}&quot;, f::&lt;u8&gt; as usize, f::&lt;u16&gt; as usize);
}"><pre class="notranslate"><code class="notranslate">trait Check: std::marker::MarkerTrait {
    fn check();
}
impl Check for u8 {
    fn check() { println!("u8"); }
}
impl Check for u16 {
    fn check() { println!("u16"); }
}

fn f&lt;T: Check&gt;() {
    T::check();
}



fn main() {
    fn same_type&lt;T&gt;(_: T, _: T) {}
    same_type(f::&lt;u8&gt;, f::&lt;u16&gt;);
    println!("{} {}", f::&lt;u8&gt; as usize, f::&lt;u16&gt; as usize);
}
</code></pre></div>
<p dir="auto">functions <code class="notranslate">f::&lt;u8&gt;</code> and <code class="notranslate">f::&lt;u16&gt;</code> have the same type <code class="notranslate">fn() {f}</code> tied to the id of the generic function item, but different function pointers. So, in general case a function pointer can't be unambiguosly obtained from function item's type.</p>
<p dir="auto">cc <a class="user-mention notranslate" data-hovercard-type="user" data-hovercard-url="/users/nikomatsakis/hovercard" data-octo-click="hovercard-link-click" data-octo-dimensions="link_type:self" href="https://github.com/nikomatsakis">@nikomatsakis</a></p>
<p dir="auto"><strong>Original title:</strong> Fn item types should be zero-sized</p>
<p dir="auto">Per <a href="https://github.com/rust-lang/rfcs/blob/master/text/0401-coercions.md#function-type-polymorphism">RFC 401</a>, every fn in Rust should have its own unique, zero-sized type. This fits with the overall design of closures, which also have their own unique types (but those types are not zero-sized, as they carry the environment). None of these types have any explicit syntax at present. This has been a longstanding plan, but until recently it was not fully implemented. This is changing with PR <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="134033337" data-permission-text="Title is private" data-url="https://github.com/rust-lang/rust/issues/31710" data-hovercard-type="pull_request" data-hovercard-url="/rust-lang/rust/pull/31710/hovercard" href="https://github.com/rust-lang/rust/pull/31710">#31710</a>, which means that some existing code will need to be adjusted to account for the new behavior. This issue attempts to summarize how things work and describe what needs to be changed.</p>
<h3 dir="auto">Zero-sized fn types</h3>
<p dir="auto">What all of this means is that, if you have a function declaration <code class="notranslate">foo</code>:</p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="// for the purposes of this discussion, all of these different kinds of `fn` declarations are equivalent:
fn foo(x: i32) { ... }
extern &quot;C&quot; fn foo(x: i32);
impl i32 { fn foo(x: self) { ... } }"><pre class="notranslate"><span class="pl-c">// for the purposes of this discussion, all of these different kinds of `fn` declarations are equivalent:</span>
<span class="pl-k">fn</span> <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">:</span> <span class="pl-smi">i32</span><span class="pl-kos">)</span> <span class="pl-kos">{</span> ..<span class="pl-kos">.</span><span class="pl-c1"></span> <span class="pl-kos">}</span>
<span class="pl-k">extern</span> <span class="pl-s">"C"</span> <span class="pl-k">fn</span> <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-s1">x</span><span class="pl-kos">:</span> <span class="pl-smi">i32</span><span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-k">impl</span> <span class="pl-smi">i32</span> <span class="pl-kos">{</span> <span class="pl-k">fn</span> foo<span class="pl-kos">(</span>x<span class="pl-kos">:</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></pre></div>
<p dir="auto">the type of <code class="notranslate">foo</code> is <strong>not</strong> <code class="notranslate">fn(i32)</code>, as one might expect. Rather, it is a unique, zero-sized marker type that I will just write as <code class="notranslate">typeof(foo)</code>. However, <code class="notranslate">typeof(foo)</code> can be <em>coerced</em> to a function pointer <code class="notranslate">fn(i32)</code>, so you rarely notice this:</p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="let x: fn(i32) = foo; // OK, coerces"><pre class="notranslate"><span class="pl-k">let</span> x<span class="pl-kos">:</span> <span class="pl-k">fn</span><span class="pl-kos">(</span><span class="pl-smi">i32</span><span class="pl-kos">)</span> = foo<span class="pl-kos">;</span> <span class="pl-c">// OK, coerces</span></pre></div>
<p dir="auto">The reason that this matter is that the type <code class="notranslate">fn(i32)</code> is not specify to any particular function: it's a function <em>pointer</em>. So calling <code class="notranslate">x()</code> results in a virtual call, whereas <code class="notranslate">foo()</code> is statically dispatched, because the type of <code class="notranslate">foo</code> tells us precisely what function is being called.</p>
<h3 dir="auto">Impact on users</h3>
<p dir="auto">As noted above, coercions mean that most code will continue to work just fine before and after this issue is fully fixed. However, you can tell the difference in a few scenarios. Perhaps the most prominent is using <strong>transmute</strong> to convert a fn item into a fn pointer. This is often done as part of an FFI:</p>
<div class="highlight highlight-source-rust notranslate position-relative overflow-auto" dir="auto" data-snippet-clipboard-copy-content="extern &quot;C&quot; fn foo(userdata: Box&lt;i32&gt;) {
   ...
}

let f: extern &quot;C&quot; fn(*mut i32) = transmute(foo);
callback(f);"><pre class="notranslate"><span class="pl-k">extern</span> <span class="pl-s">"C"</span> <span class="pl-k">fn</span> <span class="pl-en">foo</span><span class="pl-kos">(</span><span class="pl-s1">userdata</span><span class="pl-kos">:</span> <span class="pl-smi">Box</span><span class="pl-kos">&lt;</span><span class="pl-smi">i32</span><span class="pl-kos">&gt;</span><span class="pl-kos">)</span> <span class="pl-kos">{</span>
   ..<span class="pl-kos">.</span><span class="pl-c1"></span>
<span class="pl-kos">}</span>

<span class="pl-k">let</span> f<span class="pl-kos">:</span> <span class="pl-k">extern</span> <span class="pl-s">"C"</span> <span class="pl-k">fn</span><span class="pl-kos">(</span><span class="pl-c1">*</span><span class="pl-k">mut</span> <span class="pl-smi">i32</span><span class="pl-kos">)</span> = <span class="pl-en">transmute</span><span class="pl-kos">(</span>foo<span class="pl-kos">)</span><span class="pl-kos">;</span>
<span class="pl-en">callback</span><span class="pl-kos">(</span>f<span class="pl-kos">)</span><span class="pl-kos">;</span></pre></div>
<p dir="auto">Here, transmute is being used to convert the types of the fn arguments. This pattern is now incorrect because, because the type of <code class="notranslate">foo</code> is a function <strong>item</strong> (<code class="notranslate">typeof(foo)</code>), which is zero-sized, and the target type (<code class="notranslate">fn()</code>) is a function pointer, which is not zero-sized. For now, this pattern still works due to some special-cased code in the compiler, but that code is expected to be removed. For future compatibility, this pattern should be rewritten. There are a few possible ways to do this:</p>
<ul dir="auto">
<li>change the original fn declaration to match the expected signature, and do the cast in the fn body (perhaps the best);</li>
<li>cast the fn item fo a fn pointer before calling transmute, as shown here:
<ul dir="auto">
<li><code class="notranslate">let f: extern "C" fn(*mut i32) = transmute(foo as extern "C" fn(_))</code></li>
<li><code class="notranslate">let f: extern "C" fn(*mut i32) = transmute(foo as usize) /* works too */</code></li>
</ul>
</li>
</ul>
<p dir="auto">The same applies to transmutes to <code class="notranslate">*mut fn()</code>, which were observed frequently in practice. Note though that use of this type is generally incorrect. The intention is typically to describe a function pointer, but just <code class="notranslate">fn()</code> alone suffices for that. <code class="notranslate">*mut fn()</code> is a pointer to a fn pointer. (Since these values are typically just passed to C code, however, this rarely makes a difference in practice.)</p>
<h3 dir="auto">Current status and implementation trail</h3>
<ul class="contains-task-list">
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> PR <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="52041544" data-permission-text="Title is private" data-url="https://github.com/rust-lang/rust/issues/19891" data-hovercard-type="pull_request" data-hovercard-url="/rust-lang/rust/pull/19891/hovercard" href="https://github.com/rust-lang/rust/pull/19891">#19891</a> laid the groundwork with fresh, unique types per fn item, but left the back-end work undone</li>
<li class="task-list-item"><input type="checkbox" id="" disabled="" class="task-list-item-checkbox" checked=""> PR <a class="issue-link js-issue-link" data-error-text="Failed to load title" data-id="134033337" data-permission-text="Title is private" data-url="https://github.com/rust-lang/rust/issues/31710" data-hovercard-type="pull_request" data-hovercard-url="/rust-lang/rust/pull/31710/hovercard" href="https://github.com/rust-lang/rust/pull/31710">#31710</a> completes the work.</li>
</ul>