2015-01-16 14:30:27 -06:00
|
|
|
% Unsafe and Low-Level Code
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
# Introduction
|
|
|
|
|
|
|
|
Rust aims to provide safe abstractions over the low-level details of
|
2014-06-24 20:25:10 -05:00
|
|
|
the CPU and operating system, but sometimes one needs to drop down and
|
|
|
|
write code at that level. This guide aims to provide an overview of
|
|
|
|
the dangers and power one gets with Rust's unsafe subset.
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
Rust provides an escape hatch in the form of the `unsafe { ... }`
|
2014-06-24 20:25:10 -05:00
|
|
|
block which allows the programmer to dodge some of the compiler's
|
2014-03-14 10:13:48 -05:00
|
|
|
checks and do a wide range of operations, such as:
|
|
|
|
|
|
|
|
- dereferencing [raw pointers](#raw-pointers)
|
2015-01-08 12:27:03 -06:00
|
|
|
- calling a function via FFI ([covered by the FFI guide](ffi.html))
|
2014-03-14 10:13:48 -05:00
|
|
|
- casting between types bitwise (`transmute`, aka "reinterpret cast")
|
|
|
|
- [inline assembly](#inline-assembly)
|
|
|
|
|
|
|
|
Note that an `unsafe` block does not relax the rules about lifetimes
|
2014-06-24 20:25:10 -05:00
|
|
|
of `&` and the freezing of borrowed data.
|
2014-03-14 10:13:48 -05:00
|
|
|
|
2014-06-24 20:25:10 -05:00
|
|
|
Any use of `unsafe` is the programmer saying "I know more than you" to
|
|
|
|
the compiler, and, as such, the programmer should be very sure that
|
|
|
|
they actually do know more about why that piece of code is valid. In
|
|
|
|
general, one should try to minimize the amount of unsafe code in a
|
2014-03-14 10:13:48 -05:00
|
|
|
code base; preferably by using the bare minimum `unsafe` blocks to
|
|
|
|
build safe interfaces.
|
|
|
|
|
|
|
|
> **Note**: the low-level details of the Rust language are still in
|
|
|
|
> flux, and there is no guarantee of stability or backwards
|
|
|
|
> compatibility. In particular, there may be changes that do not cause
|
|
|
|
> compilation errors, but do cause semantic changes (such as invoking
|
|
|
|
> undefined behaviour). As such, extreme care is required.
|
|
|
|
|
|
|
|
# Pointers
|
|
|
|
|
|
|
|
## References
|
|
|
|
|
2014-06-24 20:25:10 -05:00
|
|
|
One of Rust's biggest features is memory safety. This is achieved in
|
2015-01-08 12:27:03 -06:00
|
|
|
part via [the ownership system](ownership.html), which is how the
|
2014-03-14 10:13:48 -05:00
|
|
|
compiler can guarantee that every `&` reference is always valid, and,
|
|
|
|
for example, never pointing to freed memory.
|
|
|
|
|
2014-06-24 20:25:10 -05:00
|
|
|
These restrictions on `&` have huge advantages. However, they also
|
|
|
|
constrain how we can use them. For example, `&` doesn't behave
|
|
|
|
identically to C's pointers, and so cannot be used for pointers in
|
|
|
|
foreign function interfaces (FFI). Additionally, both immutable (`&`)
|
|
|
|
and mutable (`&mut`) references have some aliasing and freezing
|
|
|
|
guarantees, required for memory safety.
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
In particular, if you have an `&T` reference, then the `T` must not be
|
|
|
|
modified through that reference or any other reference. There are some
|
|
|
|
standard library types, e.g. `Cell` and `RefCell`, that provide inner
|
|
|
|
mutability by replacing compile time guarantees with dynamic checks at
|
|
|
|
runtime.
|
|
|
|
|
2014-06-24 20:25:10 -05:00
|
|
|
An `&mut` reference has a different constraint: when an object has an
|
2014-03-14 10:13:48 -05:00
|
|
|
`&mut T` pointing into it, then that `&mut` reference must be the only
|
|
|
|
such usable path to that object in the whole program. That is, an
|
|
|
|
`&mut` cannot alias with any other references.
|
|
|
|
|
|
|
|
Using `unsafe` code to incorrectly circumvent and violate these
|
|
|
|
restrictions is undefined behaviour. For example, the following
|
|
|
|
creates two aliasing `&mut` pointers, and is invalid.
|
|
|
|
|
|
|
|
```
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
use std::mem;
|
2014-03-14 10:13:48 -05:00
|
|
|
let mut x: u8 = 1;
|
|
|
|
|
|
|
|
let ref_1: &mut u8 = &mut x;
|
core: Remove the cast module
This commit revisits the `cast` module in libcore and libstd, and scrutinizes
all functions inside of it. The result was to remove the `cast` module entirely,
folding all functionality into the `mem` module. Specifically, this is the fate
of each function in the `cast` module.
* transmute - This function was moved to `mem`, but it is now marked as
#[unstable]. This is due to planned changes to the `transmute`
function and how it can be invoked (see the #[unstable] comment).
For more information, see RFC 5 and #12898
* transmute_copy - This function was moved to `mem`, with clarification that is
is not an error to invoke it with T/U that are different
sizes, but rather that it is strongly discouraged. This
function is now #[stable]
* forget - This function was moved to `mem` and marked #[stable]
* bump_box_refcount - This function was removed due to the deprecation of
managed boxes as well as its questionable utility.
* transmute_mut - This function was previously deprecated, and removed as part
of this commit.
* transmute_mut_unsafe - This function doesn't serve much of a purpose when it
can be achieved with an `as` in safe code, so it was
removed.
* transmute_lifetime - This function was removed because it is likely a strong
indication that code is incorrect in the first place.
* transmute_mut_lifetime - This function was removed for the same reasons as
`transmute_lifetime`
* copy_lifetime - This function was moved to `mem`, but it is marked
`#[unstable]` now due to the likelihood of being removed in
the future if it is found to not be very useful.
* copy_mut_lifetime - This function was also moved to `mem`, but had the same
treatment as `copy_lifetime`.
* copy_lifetime_vec - This function was removed because it is not used today,
and its existence is not necessary with DST
(copy_lifetime will suffice).
In summary, the cast module was stripped down to these functions, and then the
functions were moved to the `mem` module.
transmute - #[unstable]
transmute_copy - #[stable]
forget - #[stable]
copy_lifetime - #[unstable]
copy_mut_lifetime - #[unstable]
[breaking-change]
2014-05-09 12:34:51 -05:00
|
|
|
let ref_2: &mut u8 = unsafe { mem::transmute(&mut *ref_1) };
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
// oops, ref_1 and ref_2 point to the same piece of data (x) and are
|
|
|
|
// both usable
|
|
|
|
*ref_1 = 10;
|
|
|
|
*ref_2 = 20;
|
|
|
|
```
|
|
|
|
|
|
|
|
## Raw pointers
|
|
|
|
|
2015-01-08 18:52:50 -06:00
|
|
|
Rust offers two additional pointer types (*raw pointers*), written as
|
2014-06-25 14:47:34 -05:00
|
|
|
`*const T` and `*mut T`. They're an approximation of C's `const T*` and `T*`
|
2014-03-14 10:13:48 -05:00
|
|
|
respectively; indeed, one of their most common uses is for FFI,
|
|
|
|
interfacing with external C libraries.
|
|
|
|
|
|
|
|
Raw pointers have much fewer guarantees than other pointer types
|
|
|
|
offered by the Rust language and libraries. For example, they
|
|
|
|
|
|
|
|
- are not guaranteed to point to valid memory and are not even
|
2014-05-21 22:33:11 -05:00
|
|
|
guaranteed to be non-null (unlike both `Box` and `&`);
|
|
|
|
- do not have any automatic clean-up, unlike `Box`, and so require
|
2014-03-14 10:13:48 -05:00
|
|
|
manual resource management;
|
|
|
|
- are plain-old-data, that is, they don't move ownership, again unlike
|
2014-05-21 22:33:11 -05:00
|
|
|
`Box`, hence the Rust compiler cannot protect against bugs like
|
2014-03-14 10:13:48 -05:00
|
|
|
use-after-free;
|
|
|
|
- are considered sendable (if their contents is considered sendable),
|
|
|
|
so the compiler offers no assistance with ensuring their use is
|
2015-01-13 09:40:18 -06:00
|
|
|
thread-safe; for example, one can concurrently access a `*mut i32`
|
2014-03-14 10:13:48 -05:00
|
|
|
from two threads without synchronization.
|
|
|
|
- lack any form of lifetimes, unlike `&`, and so the compiler cannot
|
|
|
|
reason about dangling pointers; and
|
|
|
|
- have no guarantees about aliasing or mutability other than mutation
|
2014-06-25 14:47:34 -05:00
|
|
|
not being allowed directly through a `*const T`.
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
Fortunately, they come with a redeeming feature: the weaker guarantees
|
|
|
|
mean weaker restrictions. The missing restrictions make raw pointers
|
2014-06-24 20:25:10 -05:00
|
|
|
appropriate as a building block for implementing things like smart
|
|
|
|
pointers and vectors inside libraries. For example, `*` pointers are
|
|
|
|
allowed to alias, allowing them to be used to write shared-ownership
|
|
|
|
types like reference counted and garbage collected pointers, and even
|
|
|
|
thread-safe shared memory types (`Rc` and the `Arc` types are both
|
|
|
|
implemented entirely in Rust).
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
There are two things that you are required to be careful about
|
|
|
|
(i.e. require an `unsafe { ... }` block) with raw pointers:
|
|
|
|
|
|
|
|
- dereferencing: they can have any value: so possible results include
|
|
|
|
a crash, a read of uninitialised memory, a use-after-free, or
|
2014-06-24 20:25:10 -05:00
|
|
|
reading data as normal.
|
2014-03-14 10:13:48 -05:00
|
|
|
- pointer arithmetic via the `offset` [intrinsic](#intrinsics) (or
|
|
|
|
`.offset` method): this intrinsic uses so-called "in-bounds"
|
|
|
|
arithmetic, that is, it is only defined behaviour if the result is
|
|
|
|
inside (or one-byte-past-the-end) of the object from which the
|
|
|
|
original pointer came.
|
|
|
|
|
|
|
|
The latter assumption allows the compiler to optimize more
|
|
|
|
effectively. As can be seen, actually *creating* a raw pointer is not
|
|
|
|
unsafe, and neither is converting to an integer.
|
|
|
|
|
|
|
|
### References and raw pointers
|
|
|
|
|
|
|
|
At runtime, a raw pointer `*` and a reference pointing to the same
|
|
|
|
piece of data have an identical representation. In fact, an `&T`
|
2014-06-25 14:47:34 -05:00
|
|
|
reference will implicitly coerce to an `*const T` raw pointer in safe code
|
2014-03-14 10:13:48 -05:00
|
|
|
and similarly for the `mut` variants (both coercions can be performed
|
2014-06-25 14:47:34 -05:00
|
|
|
explicitly with, respectively, `value as *const T` and `value as *mut T`).
|
2014-03-14 10:13:48 -05:00
|
|
|
|
2014-06-25 14:47:34 -05:00
|
|
|
Going the opposite direction, from `*const` to a reference `&`, is not
|
2014-03-14 10:13:48 -05:00
|
|
|
safe. A `&T` is always valid, and so, at a minimum, the raw pointer
|
2014-08-12 14:30:02 -05:00
|
|
|
`*const T` has to point to a valid instance of type `T`. Furthermore,
|
2014-03-14 10:13:48 -05:00
|
|
|
the resulting pointer must satisfy the aliasing and mutability laws of
|
|
|
|
references. The compiler assumes these properties are true for any
|
|
|
|
references, no matter how they are created, and so any conversion from
|
|
|
|
raw pointers is asserting that they hold. The programmer *must*
|
|
|
|
guarantee this.
|
|
|
|
|
|
|
|
The recommended method for the conversion is
|
|
|
|
|
|
|
|
```
|
|
|
|
let i: u32 = 1;
|
|
|
|
// explicit cast
|
2014-06-25 14:47:34 -05:00
|
|
|
let p_imm: *const u32 = &i as *const u32;
|
2014-03-14 10:13:48 -05:00
|
|
|
let mut m: u32 = 2;
|
|
|
|
// implicit coercion
|
|
|
|
let p_mut: *mut u32 = &mut m;
|
|
|
|
|
|
|
|
unsafe {
|
|
|
|
let ref_imm: &u32 = &*p_imm;
|
|
|
|
let ref_mut: &mut u32 = &mut *p_mut;
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
The `&*x` dereferencing style is preferred to using a `transmute`.
|
|
|
|
The latter is far more powerful than necessary, and the more
|
|
|
|
restricted operation is harder to use incorrectly; for example, it
|
|
|
|
requires that `x` is a pointer (unlike `transmute`).
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
## Making the unsafe safe(r)
|
|
|
|
|
|
|
|
There are various ways to expose a safe interface around some unsafe
|
|
|
|
code:
|
|
|
|
|
|
|
|
- store pointers privately (i.e. not in public fields of public
|
|
|
|
structs), so that you can see and control all reads and writes to
|
|
|
|
the pointer in one place.
|
2014-06-24 20:25:10 -05:00
|
|
|
- use `assert!()` a lot: since you can't rely on the protection of the
|
|
|
|
compiler & type-system to ensure that your `unsafe` code is correct
|
|
|
|
at compile-time, use `assert!()` to verify that it is doing the
|
|
|
|
right thing at run-time.
|
2014-03-14 10:13:48 -05:00
|
|
|
- implement the `Drop` for resource clean-up via a destructor, and use
|
|
|
|
RAII (Resource Acquisition Is Initialization). This reduces the need
|
|
|
|
for any manual memory management by users, and automatically ensures
|
2015-01-10 03:45:51 -06:00
|
|
|
that clean-up is always run, even when the thread panics.
|
2014-03-14 10:13:48 -05:00
|
|
|
- ensure that any data stored behind a raw pointer is destroyed at the
|
|
|
|
appropriate time.
|
|
|
|
|
|
|
|
As an example, we give a reimplementation of owned boxes by wrapping
|
|
|
|
`malloc` and `free`. Rust's move semantics and lifetimes mean this
|
2014-05-21 22:33:11 -05:00
|
|
|
reimplementation is as safe as the `Box` type.
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
```
|
2014-06-17 18:00:04 -05:00
|
|
|
#![feature(unsafe_destructor)]
|
|
|
|
|
2014-02-26 11:58:41 -06:00
|
|
|
extern crate libc;
|
|
|
|
use libc::{c_void, size_t, malloc, free};
|
2014-03-14 10:13:48 -05:00
|
|
|
use std::mem;
|
|
|
|
use std::ptr;
|
|
|
|
|
|
|
|
// Define a wrapper around the handle returned by the foreign code.
|
2014-05-21 22:33:11 -05:00
|
|
|
// Unique<T> has the same semantics as Box<T>
|
2014-03-14 10:13:48 -05:00
|
|
|
pub struct Unique<T> {
|
|
|
|
// It contains a single raw, mutable pointer to the object in question.
|
2014-03-28 17:00:40 -05:00
|
|
|
ptr: *mut T
|
2014-03-14 10:13:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
// Implement methods for creating and using the values in the box.
|
2014-05-21 22:33:11 -05:00
|
|
|
|
2014-03-14 10:13:48 -05:00
|
|
|
// NB: For simplicity and correctness, we require that T has kind Send
|
2014-09-30 17:45:17 -05:00
|
|
|
// (owned boxes relax this restriction).
|
2014-03-14 10:13:48 -05:00
|
|
|
impl<T: Send> Unique<T> {
|
|
|
|
pub fn new(value: T) -> Unique<T> {
|
|
|
|
unsafe {
|
2014-05-29 19:40:18 -05:00
|
|
|
let ptr = malloc(mem::size_of::<T>() as size_t) as *mut T;
|
2014-03-14 10:13:48 -05:00
|
|
|
// we *need* valid pointer.
|
|
|
|
assert!(!ptr.is_null());
|
2014-05-21 22:33:11 -05:00
|
|
|
// `*ptr` is uninitialized, and `*ptr = value` would
|
|
|
|
// attempt to destroy it `overwrite` moves a value into
|
|
|
|
// this memory without attempting to drop the original
|
|
|
|
// value.
|
2014-05-29 19:40:18 -05:00
|
|
|
ptr::write(&mut *ptr, value);
|
2014-03-14 10:13:48 -05:00
|
|
|
Unique{ptr: ptr}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
// the 'r lifetime results in the same semantics as `&*x` with
|
|
|
|
// Box<T>
|
2014-03-14 10:13:48 -05:00
|
|
|
pub fn borrow<'r>(&'r self) -> &'r T {
|
|
|
|
// By construction, self.ptr is valid
|
|
|
|
unsafe { &*self.ptr }
|
|
|
|
}
|
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
// the 'r lifetime results in the same semantics as `&mut *x` with
|
|
|
|
// Box<T>
|
2014-03-14 10:13:48 -05:00
|
|
|
pub fn borrow_mut<'r>(&'r mut self) -> &'r mut T {
|
2014-05-21 22:33:11 -05:00
|
|
|
unsafe { &mut *self.ptr }
|
2014-03-14 10:13:48 -05:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// A key ingredient for safety, we associate a destructor with
|
|
|
|
// Unique<T>, making the struct manage the raw pointer: when the
|
|
|
|
// struct goes out of scope, it will automatically free the raw pointer.
|
2014-06-17 18:00:04 -05:00
|
|
|
//
|
2014-03-14 10:13:48 -05:00
|
|
|
// NB: This is an unsafe destructor, because rustc will not normally
|
2014-06-17 18:00:04 -05:00
|
|
|
// allow destructors to be associated with parameterized types, due to
|
2014-03-14 10:13:48 -05:00
|
|
|
// bad interaction with managed boxes. (With the Send restriction,
|
2014-06-17 18:00:04 -05:00
|
|
|
// we don't have this problem.) Note that the `#[unsafe_destructor]`
|
|
|
|
// feature gate is required to use unsafe destructors.
|
2014-03-14 10:13:48 -05:00
|
|
|
#[unsafe_destructor]
|
|
|
|
impl<T: Send> Drop for Unique<T> {
|
|
|
|
fn drop(&mut self) {
|
|
|
|
unsafe {
|
|
|
|
// Copy the object out from the pointer onto the stack,
|
|
|
|
// where it is covered by normal Rust destructor semantics
|
|
|
|
// and cleans itself up, if necessary
|
2015-01-16 22:34:10 -06:00
|
|
|
ptr::read(self.ptr);
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
// clean-up our allocation
|
|
|
|
free(self.ptr as *mut c_void)
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
2014-05-05 20:56:44 -05:00
|
|
|
// A comparison between the built-in `Box` and this reimplementation
|
2014-03-14 10:13:48 -05:00
|
|
|
fn main() {
|
|
|
|
{
|
2015-01-13 09:40:18 -06:00
|
|
|
let mut x = Box::new(5);
|
2014-03-14 10:13:48 -05:00
|
|
|
*x = 10;
|
|
|
|
} // `x` is freed here
|
|
|
|
|
|
|
|
{
|
2015-01-13 09:40:18 -06:00
|
|
|
let mut y = Unique::new(5);
|
2014-03-14 10:13:48 -05:00
|
|
|
*y.borrow_mut() = 10;
|
|
|
|
} // `y` is freed here
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
Notably, the only way to construct a `Unique` is via the `new`
|
|
|
|
function, and this function ensures that the internal pointer is valid
|
|
|
|
and hidden in the private field. The two `borrow` methods are safe
|
|
|
|
because the compiler statically guarantees that objects are never used
|
|
|
|
before creation or after destruction (unless you use some `unsafe`
|
|
|
|
code...).
|
|
|
|
|
|
|
|
# Inline assembly
|
|
|
|
|
|
|
|
For extremely low-level manipulations and performance reasons, one
|
|
|
|
might wish to control the CPU directly. Rust supports using inline
|
|
|
|
assembly to do this via the `asm!` macro. The syntax roughly matches
|
|
|
|
that of GCC & Clang:
|
|
|
|
|
|
|
|
```ignore
|
|
|
|
asm!(assembly template
|
|
|
|
: output operands
|
|
|
|
: input operands
|
|
|
|
: clobbers
|
|
|
|
: options
|
|
|
|
);
|
|
|
|
```
|
|
|
|
|
2014-04-03 19:55:06 -05:00
|
|
|
Any use of `asm` is feature gated (requires `#![feature(asm)]` on the
|
2014-03-14 10:13:48 -05:00
|
|
|
crate to allow) and of course requires an `unsafe` block.
|
|
|
|
|
2014-06-24 20:25:10 -05:00
|
|
|
> **Note**: the examples here are given in x86/x86-64 assembly, but
|
|
|
|
> all platforms are supported.
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
## Assembly template
|
|
|
|
|
|
|
|
The `assembly template` is the only required parameter and must be a
|
|
|
|
literal string (i.e `""`)
|
|
|
|
|
|
|
|
```
|
2014-04-03 19:55:06 -05:00
|
|
|
#![feature(asm)]
|
2014-03-14 10:13:48 -05:00
|
|
|
|
2014-10-11 20:05:54 -05:00
|
|
|
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
2014-03-14 10:13:48 -05:00
|
|
|
fn foo() {
|
|
|
|
unsafe {
|
|
|
|
asm!("NOP");
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
// other platforms
|
2014-10-11 20:05:54 -05:00
|
|
|
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
2014-03-14 10:13:48 -05:00
|
|
|
fn foo() { /* ... */ }
|
|
|
|
|
|
|
|
fn main() {
|
|
|
|
// ...
|
|
|
|
foo();
|
|
|
|
// ...
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
(The `feature(asm)` and `#[cfg]`s are omitted from now on.)
|
|
|
|
|
|
|
|
Output operands, input operands, clobbers and options are all optional
|
|
|
|
but you must add the right number of `:` if you skip them:
|
|
|
|
|
|
|
|
```
|
2014-04-03 19:55:06 -05:00
|
|
|
# #![feature(asm)]
|
2014-10-11 20:05:54 -05:00
|
|
|
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
2014-03-14 10:13:48 -05:00
|
|
|
# fn main() { unsafe {
|
|
|
|
asm!("xor %eax, %eax"
|
|
|
|
:
|
|
|
|
:
|
|
|
|
: "eax"
|
|
|
|
);
|
|
|
|
# } }
|
|
|
|
```
|
|
|
|
|
|
|
|
Whitespace also doesn't matter:
|
|
|
|
|
|
|
|
```
|
2014-04-03 19:55:06 -05:00
|
|
|
# #![feature(asm)]
|
2014-10-11 20:05:54 -05:00
|
|
|
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
2014-03-14 10:13:48 -05:00
|
|
|
# fn main() { unsafe {
|
|
|
|
asm!("xor %eax, %eax" ::: "eax");
|
|
|
|
# } }
|
|
|
|
```
|
|
|
|
|
|
|
|
## Operands
|
|
|
|
|
|
|
|
Input and output operands follow the same format: `:
|
|
|
|
"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
|
|
|
|
expressions must be mutable lvalues:
|
|
|
|
|
|
|
|
```
|
2014-04-03 19:55:06 -05:00
|
|
|
# #![feature(asm)]
|
2014-10-11 20:05:54 -05:00
|
|
|
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
2015-01-13 09:40:18 -06:00
|
|
|
fn add(a: i32, b: i32) -> i32 {
|
2014-03-14 10:13:48 -05:00
|
|
|
let mut c = 0;
|
|
|
|
unsafe {
|
|
|
|
asm!("add $2, $0"
|
|
|
|
: "=r"(c)
|
|
|
|
: "0"(a), "r"(b)
|
|
|
|
);
|
|
|
|
}
|
|
|
|
c
|
|
|
|
}
|
2014-10-11 20:05:54 -05:00
|
|
|
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
2015-01-13 09:40:18 -06:00
|
|
|
# fn add(a: i32, b: i32) -> i32 { a + b }
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
fn main() {
|
|
|
|
assert_eq!(add(3, 14159), 14162)
|
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
## Clobbers
|
|
|
|
|
|
|
|
Some instructions modify registers which might otherwise have held
|
|
|
|
different values so we use the clobbers list to indicate to the
|
|
|
|
compiler not to assume any values loaded into those registers will
|
|
|
|
stay valid.
|
|
|
|
|
|
|
|
```
|
2014-04-03 19:55:06 -05:00
|
|
|
# #![feature(asm)]
|
2014-10-11 20:05:54 -05:00
|
|
|
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
2014-03-14 10:13:48 -05:00
|
|
|
# fn main() { unsafe {
|
|
|
|
// Put the value 0x200 in eax
|
|
|
|
asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
|
|
|
|
# } }
|
|
|
|
```
|
|
|
|
|
|
|
|
Input and output registers need not be listed since that information
|
|
|
|
is already communicated by the given constraints. Otherwise, any other
|
|
|
|
registers used either implicitly or explicitly should be listed.
|
|
|
|
|
|
|
|
If the assembly changes the condition code register `cc` should be
|
|
|
|
specified as one of the clobbers. Similarly, if the assembly modifies
|
|
|
|
memory, `memory` should also be specified.
|
|
|
|
|
|
|
|
## Options
|
|
|
|
|
|
|
|
The last section, `options` is specific to Rust. The format is comma
|
|
|
|
separated literal strings (i.e `:"foo", "bar", "baz"`). It's used to
|
|
|
|
specify some extra info about the inline assembly:
|
|
|
|
|
|
|
|
Current valid options are:
|
|
|
|
|
2015-01-08 18:52:50 -06:00
|
|
|
1. *volatile* - specifying this is analogous to
|
|
|
|
`__asm__ __volatile__ (...)` in gcc/clang.
|
|
|
|
2. *alignstack* - certain instructions expect the stack to be
|
2014-03-14 10:13:48 -05:00
|
|
|
aligned a certain way (i.e SSE) and specifying this indicates to
|
|
|
|
the compiler to insert its usual stack alignment code
|
2015-01-08 18:52:50 -06:00
|
|
|
3. *intel* - use intel syntax instead of the default AT&T.
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
# Avoiding the standard library
|
|
|
|
|
|
|
|
By default, `std` is linked to every Rust crate. In some contexts,
|
2014-04-11 22:33:16 -05:00
|
|
|
this is undesirable, and can be avoided with the `#![no_std]`
|
2014-03-14 10:13:48 -05:00
|
|
|
attribute attached to the crate.
|
|
|
|
|
|
|
|
```ignore
|
2014-05-21 22:33:11 -05:00
|
|
|
// a minimal library
|
2014-04-11 22:33:16 -05:00
|
|
|
#![crate_type="lib"]
|
|
|
|
#![no_std]
|
2014-03-14 10:13:48 -05:00
|
|
|
# // fn main() {} tricked you, rustdoc!
|
|
|
|
```
|
|
|
|
|
|
|
|
Obviously there's more to life than just libraries: one can use
|
|
|
|
`#[no_std]` with an executable, controlling the entry point is
|
|
|
|
possible in two ways: the `#[start]` attribute, or overriding the
|
|
|
|
default shim for the C `main` function with your own.
|
|
|
|
|
|
|
|
The function marked `#[start]` is passed the command line parameters
|
2014-08-19 18:31:07 -05:00
|
|
|
in the same format as C:
|
2014-03-14 10:13:48 -05:00
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
```
|
2014-04-11 22:33:16 -05:00
|
|
|
#![no_std]
|
2015-01-16 12:55:24 -06:00
|
|
|
#![feature(lang_items, start)]
|
2014-03-14 10:13:48 -05:00
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
// Pull in the system libc library for what crt0.o likely requires
|
|
|
|
extern crate libc;
|
2014-03-14 10:13:48 -05:00
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
// Entry point for this program
|
2014-03-14 10:13:48 -05:00
|
|
|
#[start]
|
2015-01-13 09:40:18 -06:00
|
|
|
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
2014-03-14 10:13:48 -05:00
|
|
|
0
|
|
|
|
}
|
|
|
|
|
2014-09-15 17:52:20 -05:00
|
|
|
// These functions and traits are used by the compiler, but not
|
2014-05-21 22:33:11 -05:00
|
|
|
// for a bare-bones hello world. These are normally
|
|
|
|
// provided by libstd.
|
|
|
|
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
|
|
|
#[lang = "eh_personality"] extern fn eh_personality() {}
|
2014-10-28 13:07:33 -05:00
|
|
|
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
|
2014-03-14 10:13:48 -05:00
|
|
|
# // fn main() {} tricked you, rustdoc!
|
|
|
|
```
|
|
|
|
|
|
|
|
To override the compiler-inserted `main` shim, one has to disable it
|
2014-04-11 22:33:16 -05:00
|
|
|
with `#![no_main]` and then create the appropriate symbol with the
|
2014-03-14 10:13:48 -05:00
|
|
|
correct ABI and the correct name, which requires overriding the
|
|
|
|
compiler's name mangling too:
|
|
|
|
|
|
|
|
```ignore
|
2014-04-11 22:33:16 -05:00
|
|
|
#![no_std]
|
|
|
|
#![no_main]
|
2015-01-16 12:55:24 -06:00
|
|
|
#![feature(lang_items, start)]
|
2014-03-14 10:13:48 -05:00
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
extern crate libc;
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
#[no_mangle] // ensure that this symbol is called `main` in the output
|
2015-01-13 09:40:18 -06:00
|
|
|
pub extern fn main(argc: i32, argv: *const *const u8) -> i32 {
|
2014-03-14 10:13:48 -05:00
|
|
|
0
|
|
|
|
}
|
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
|
|
|
#[lang = "eh_personality"] extern fn eh_personality() {}
|
2014-10-28 13:07:33 -05:00
|
|
|
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
|
2014-03-14 10:13:48 -05:00
|
|
|
# // fn main() {} tricked you, rustdoc!
|
|
|
|
```
|
|
|
|
|
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
The compiler currently makes a few assumptions about symbols which are available
|
|
|
|
in the executable to call. Normally these functions are provided by the standard
|
2014-09-25 12:59:24 -05:00
|
|
|
library, but without it you must define your own.
|
2014-05-21 22:33:11 -05:00
|
|
|
|
2014-09-25 12:59:24 -05:00
|
|
|
The first of these three functions, `stack_exhausted`, is invoked whenever stack
|
2014-05-21 22:33:11 -05:00
|
|
|
overflow is detected. This function has a number of restrictions about how it
|
|
|
|
can be called and what it must do, but if the stack limit register is not being
|
2015-01-10 03:45:51 -06:00
|
|
|
maintained then a thread always has an "infinite stack" and this function
|
2014-05-21 22:33:11 -05:00
|
|
|
shouldn't get triggered.
|
|
|
|
|
2014-09-25 12:59:24 -05:00
|
|
|
The second of these three functions, `eh_personality`, is used by the
|
|
|
|
failure mechanisms of the compiler. This is often mapped to GCC's
|
|
|
|
personality function (see the
|
2015-01-08 12:27:03 -06:00
|
|
|
[libstd implementation](../std/rt/unwind/index.html) for more
|
2014-10-09 14:17:22 -05:00
|
|
|
information), but crates which do not trigger a panic can be assured
|
2014-10-28 13:07:33 -05:00
|
|
|
that this function is never called. The final function, `panic_fmt`, is
|
2014-09-25 12:59:24 -05:00
|
|
|
also used by the failure mechanisms of the compiler.
|
2014-09-15 17:52:20 -05:00
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
## Using libcore
|
|
|
|
|
|
|
|
> **Note**: the core library's structure is unstable, and it is recommended to
|
|
|
|
> use the standard library instead wherever possible.
|
|
|
|
|
|
|
|
With the above techniques, we've got a bare-metal executable running some Rust
|
|
|
|
code. There is a good deal of functionality provided by the standard library,
|
|
|
|
however, that is necessary to be productive in Rust. If the standard library is
|
2015-01-08 12:27:03 -06:00
|
|
|
not sufficient, then [libcore](../core/index.html) is designed to be used
|
2014-05-29 11:58:09 -05:00
|
|
|
instead.
|
2014-05-21 22:33:11 -05:00
|
|
|
|
|
|
|
The core library has very few dependencies and is much more portable than the
|
|
|
|
standard library itself. Additionally, the core library has most of the
|
|
|
|
necessary functionality for writing idiomatic and effective Rust code.
|
|
|
|
|
|
|
|
As an example, here is a program that will calculate the dot product of two
|
|
|
|
vectors provided from C, using idiomatic Rust practices.
|
|
|
|
|
|
|
|
```
|
|
|
|
#![no_std]
|
2015-01-16 12:55:24 -06:00
|
|
|
#![feature(lang_items, start)]
|
2014-05-21 22:33:11 -05:00
|
|
|
|
|
|
|
# extern crate libc;
|
|
|
|
extern crate core;
|
|
|
|
|
|
|
|
use core::prelude::*;
|
|
|
|
|
|
|
|
use core::mem;
|
|
|
|
|
|
|
|
#[no_mangle]
|
2014-06-25 14:47:34 -05:00
|
|
|
pub extern fn dot_product(a: *const u32, a_len: u32,
|
|
|
|
b: *const u32, b_len: u32) -> u32 {
|
2014-08-12 22:31:30 -05:00
|
|
|
use core::raw::Slice;
|
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
// Convert the provided arrays into Rust slices.
|
|
|
|
// The core::raw module guarantees that the Slice
|
|
|
|
// structure has the same memory layout as a &[T]
|
|
|
|
// slice.
|
|
|
|
//
|
|
|
|
// This is an unsafe operation because the compiler
|
|
|
|
// cannot tell the pointers are valid.
|
|
|
|
let (a_slice, b_slice): (&[u32], &[u32]) = unsafe {
|
|
|
|
mem::transmute((
|
2015-01-13 09:40:18 -06:00
|
|
|
Slice { data: a, len: a_len as usize },
|
|
|
|
Slice { data: b, len: b_len as usize },
|
2014-05-21 22:33:11 -05:00
|
|
|
))
|
|
|
|
};
|
|
|
|
|
|
|
|
// Iterate over the slices, collecting the result
|
|
|
|
let mut ret = 0;
|
|
|
|
for (i, j) in a_slice.iter().zip(b_slice.iter()) {
|
|
|
|
ret += (*i) * (*j);
|
|
|
|
}
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2014-10-28 13:07:33 -05:00
|
|
|
#[lang = "panic_fmt"]
|
|
|
|
extern fn panic_fmt(args: &core::fmt::Arguments,
|
2015-01-04 11:31:02 -06:00
|
|
|
file: &str,
|
|
|
|
line: u32) -> ! {
|
2014-05-21 22:33:11 -05:00
|
|
|
loop {}
|
|
|
|
}
|
|
|
|
|
|
|
|
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
|
|
|
#[lang = "eh_personality"] extern fn eh_personality() {}
|
2015-01-13 09:40:18 -06:00
|
|
|
# #[start] fn start(argc: isize, argv: *const *const u8) -> isize { 0 }
|
2014-05-21 22:33:11 -05:00
|
|
|
# fn main() {}
|
|
|
|
```
|
|
|
|
|
|
|
|
Note that there is one extra lang item here which differs from the examples
|
2014-10-28 13:07:33 -05:00
|
|
|
above, `panic_fmt`. This must be defined by consumers of libcore because the
|
|
|
|
core library declares panics, but it does not define it. The `panic_fmt`
|
|
|
|
lang item is this crate's definition of panic, and it must be guaranteed to
|
2014-05-21 22:33:11 -05:00
|
|
|
never return.
|
|
|
|
|
|
|
|
As can be seen in this example, the core library is intended to provide the
|
|
|
|
power of Rust in all circumstances, regardless of platform requirements. Further
|
|
|
|
libraries, such as liballoc, add functionality to libcore which make other
|
|
|
|
platform-specific assumptions, but continue to be more portable than the
|
|
|
|
standard library itself.
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
# Interacting with the compiler internals
|
|
|
|
|
|
|
|
> **Note**: this section is specific to the `rustc` compiler; these
|
2014-08-19 18:31:07 -05:00
|
|
|
> parts of the language may never be fully specified and so details may
|
2014-03-14 10:13:48 -05:00
|
|
|
> differ wildly between implementations (and even versions of `rustc`
|
|
|
|
> itself).
|
2014-06-25 14:47:34 -05:00
|
|
|
>
|
2014-03-14 10:13:48 -05:00
|
|
|
> Furthermore, this is just an overview; the best form of
|
|
|
|
> documentation for specific instances of these features are their
|
|
|
|
> definitions and uses in `std`.
|
|
|
|
|
|
|
|
The Rust language currently has two orthogonal mechanisms for allowing
|
|
|
|
libraries to interact directly with the compiler and vice versa:
|
|
|
|
|
|
|
|
- intrinsics, functions built directly into the compiler providing
|
|
|
|
very basic low-level functionality,
|
|
|
|
- lang-items, special functions, types and traits in libraries marked
|
|
|
|
with specific `#[lang]` attributes
|
|
|
|
|
|
|
|
## Intrinsics
|
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
> **Note**: intrinsics will forever have an unstable interface, it is
|
|
|
|
> recommended to use the stable interfaces of libcore rather than intrinsics
|
|
|
|
> directly.
|
|
|
|
|
2014-03-14 10:13:48 -05:00
|
|
|
These are imported as if they were FFI functions, with the special
|
|
|
|
`rust-intrinsic` ABI. For example, if one was in a freestanding
|
|
|
|
context, but wished to be able to `transmute` between types, and
|
|
|
|
perform efficient pointer arithmetic, one would import those functions
|
|
|
|
via a declaration like
|
|
|
|
|
|
|
|
```
|
2014-06-20 18:39:23 -05:00
|
|
|
# #![feature(intrinsics)]
|
|
|
|
# fn main() {}
|
|
|
|
|
2014-03-14 10:13:48 -05:00
|
|
|
extern "rust-intrinsic" {
|
|
|
|
fn transmute<T, U>(x: T) -> U;
|
|
|
|
|
2015-01-13 09:40:18 -06:00
|
|
|
fn offset<T>(dst: *const T, offset: isize) -> *const T;
|
2014-03-14 10:13:48 -05:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
As with any other FFI functions, these are always `unsafe` to call.
|
|
|
|
|
|
|
|
## Lang items
|
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
> **Note**: lang items are often provided by crates in the Rust distribution,
|
|
|
|
> and lang items themselves have an unstable interface. It is recommended to use
|
|
|
|
> officially distributed crates instead of defining your own lang items.
|
|
|
|
|
2014-03-14 10:13:48 -05:00
|
|
|
The `rustc` compiler has certain pluggable operations, that is,
|
|
|
|
functionality that isn't hard-coded into the language, but is
|
|
|
|
implemented in libraries, with a special marker to tell the compiler
|
|
|
|
it exists. The marker is the attribute `#[lang="..."]` and there are
|
|
|
|
various different values of `...`, i.e. various different "lang
|
|
|
|
items".
|
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
For example, `Box` pointers require two lang items, one for allocation
|
|
|
|
and one for deallocation. A freestanding program that uses the `Box`
|
2014-03-14 10:13:48 -05:00
|
|
|
sugar for dynamic allocations via `malloc` and `free`:
|
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
```
|
2014-04-11 22:33:16 -05:00
|
|
|
#![no_std]
|
2015-01-16 12:55:24 -06:00
|
|
|
#![feature(lang_items, box_syntax, start)]
|
2014-03-14 10:13:48 -05:00
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
extern crate libc;
|
2014-03-14 10:13:48 -05:00
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
extern {
|
2014-03-14 10:13:48 -05:00
|
|
|
fn abort() -> !;
|
|
|
|
}
|
|
|
|
|
librustc: Make `Copy` opt-in.
This change makes the compiler no longer infer whether types (structures
and enumerations) implement the `Copy` trait (and thus are implicitly
copyable). Rather, you must implement `Copy` yourself via `impl Copy for
MyType {}`.
A new warning has been added, `missing_copy_implementations`, to warn
you if a non-generic public type has been added that could have
implemented `Copy` but didn't.
For convenience, you may *temporarily* opt out of this behavior by using
`#![feature(opt_out_copy)]`. Note though that this feature gate will never be
accepted and will be removed by the time that 1.0 is released, so you should
transition your code away from using it.
This breaks code like:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
Change this code to:
#[deriving(Show)]
struct Point2D {
x: int,
y: int,
}
impl Copy for Point2D {}
fn main() {
let mypoint = Point2D {
x: 1,
y: 1,
};
let otherpoint = mypoint;
println!("{}{}", mypoint, otherpoint);
}
This is the backwards-incompatible part of #13231.
Part of RFC #3.
[breaking-change]
2014-12-05 19:01:33 -06:00
|
|
|
#[lang = "owned_box"]
|
|
|
|
pub struct Box<T>(*mut T);
|
|
|
|
|
2014-03-14 10:13:48 -05:00
|
|
|
#[lang="exchange_malloc"]
|
2015-01-13 09:40:18 -06:00
|
|
|
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
|
2014-05-21 22:33:11 -05:00
|
|
|
let p = libc::malloc(size as libc::size_t) as *mut u8;
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
// malloc failed
|
2015-01-13 09:40:18 -06:00
|
|
|
if p as usize == 0 {
|
2014-03-14 10:13:48 -05:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
p
|
|
|
|
}
|
|
|
|
#[lang="exchange_free"]
|
2015-01-13 09:40:18 -06:00
|
|
|
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
|
2014-05-21 22:33:11 -05:00
|
|
|
libc::free(ptr as *mut libc::c_void)
|
2014-03-14 10:13:48 -05:00
|
|
|
}
|
|
|
|
|
|
|
|
#[start]
|
2015-01-13 09:40:18 -06:00
|
|
|
fn main(argc: isize, argv: *const *const u8) -> isize {
|
|
|
|
let x = box 1;
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
0
|
|
|
|
}
|
|
|
|
|
2014-05-21 22:33:11 -05:00
|
|
|
#[lang = "stack_exhausted"] extern fn stack_exhausted() {}
|
|
|
|
#[lang = "eh_personality"] extern fn eh_personality() {}
|
2014-10-28 13:07:33 -05:00
|
|
|
#[lang = "panic_fmt"] fn panic_fmt() -> ! { loop {} }
|
2014-03-14 10:13:48 -05:00
|
|
|
```
|
|
|
|
|
|
|
|
Note the use of `abort`: the `exchange_malloc` lang item is assumed to
|
2014-06-24 20:25:10 -05:00
|
|
|
return a valid pointer, and so needs to do the check internally.
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
Other features provided by lang items include:
|
|
|
|
|
|
|
|
- overloadable operators via traits: the traits corresponding to the
|
|
|
|
`==`, `<`, dereferencing (`*`) and `+` (etc.) operators are all
|
|
|
|
marked with lang items; those specific four are `eq`, `ord`,
|
|
|
|
`deref`, and `add` respectively.
|
2014-09-21 16:35:43 -05:00
|
|
|
- stack unwinding and general failure; the `eh_personality`, `fail`
|
2014-03-14 10:13:48 -05:00
|
|
|
and `fail_bounds_checks` lang items.
|
2015-01-18 08:17:44 -06:00
|
|
|
- the traits in `std::marker` used to indicate types of
|
2014-08-05 18:40:04 -05:00
|
|
|
various kinds; lang items `send`, `sync` and `copy`.
|
2014-03-14 10:13:48 -05:00
|
|
|
- the marker types and variance indicators found in
|
2015-01-18 08:17:44 -06:00
|
|
|
`std::marker`; lang items `covariant_type`,
|
2014-08-05 18:40:04 -05:00
|
|
|
`contravariant_lifetime`, `no_sync_bound`, etc.
|
2014-03-14 10:13:48 -05:00
|
|
|
|
|
|
|
Lang items are loaded lazily by the compiler; e.g. if one never uses
|
2014-05-21 22:33:11 -05:00
|
|
|
`Box` then there is no need to define functions for `exchange_malloc`
|
2014-03-14 10:13:48 -05:00
|
|
|
and `exchange_free`. `rustc` will emit an error when an item is needed
|
|
|
|
but not found in the current crate or any that it depends on.
|