Note: this RFC was never implemented and has been retired. The design may still be useful in the future, but before implementing we would prefer to revisit it so as to be sure it is up to date.

Summary

The way our intrinsics work forces them to be wrapped in order to behave like normal functions. As a result, rustc is forced to inline a great number of tiny intrinsic wrappers, which is bad for both compile-time performance and runtime performance without optimizations. This proposal changes the way intrinsics are surfaced in the language so that they behave the same as normal Rust functions by removing the “rust-intrinsic” foreign ABI and reusing the “Rust” ABI.

Motivation

A number of commonly-used intrinsics, including transmute, forget, init, uninit, and move_val_init, are accessed through wrappers whose only purpose is to present the intrinsics as normal functions. As a result, rustc is forced to inline a great number of tiny intrinsic wrappers, which is bad for both compile-time performance and runtime performance without optimizations.

Intrinsics have a differently-named ABI from Rust functions (“rust-intrinsic” vs. “Rust”) though the actual ABI implementation is identical. As a result one can’t take the value of an intrinsic as a function:

// error: the type of transmute is `extern "rust-intrinsic" fn ...`
let transmute: fn(int) -> uint = intrinsics::transmute;

This incongruity means that we can’t just expose the intrinsics directly as part of the public API.

Detailed design

extern "Rust" fn is already equivalent to fn, so if intrinsics have the “Rust” ABI then the problem is solved.

Under this scheme intrinsics will be declared as extern "Rust" functions and identified as intrinsics with the #[lang = "..."] attribute:

extern "Rust" {
    #[lang = "transmute"]
    fn transmute<T, U>(T) -> U;
}

The compiler will type check and translate intrinsics the same as today. Additionally, when trans sees a “Rust” extern tagged as an intrinsic it will not emit a function declaration to LLVM bitcode.

Because intrinsics will be lang items, they can no longer be redeclared arbitrary number of times. This will require a small amount of existing library code to be refactored, and all intrinsics to be exposed through public abstractions.

Currently, “Rust” foreign functions may not be generic; this change will require a special case that allows intrinsics to be generic.

Alternatives

  1. Instead of making intrinsics lang items we could create a slightly different mechanism, like an #[intrinsic] attribute, that would continue letting intrinsics to be redeclared.

  2. While using lang items to identify intrinsics, intrinsic lang items could be allowed to be redeclared.

  3. We could also make “rust-intrinsic” coerce or otherwise be the same as “Rust” externs and normal Rust functions.

Unresolved questions

None.