TRPL Nightly -> Unstable Book
Port the chapters from TRPL's "Nightly Rust" section to the Unstable Book, and remove it from TRPL.
This commit is contained in:
parent
aba4bf60f5
commit
6fb2545f77
@ -55,18 +55,6 @@
|
||||
* [Release Channels](release-channels.md)
|
||||
* [Using Rust without the standard library](using-rust-without-the-standard-library.md)
|
||||
* [Procedural Macros (and custom derive)](procedural-macros.md)
|
||||
* [Nightly Rust](nightly-rust.md)
|
||||
* [Compiler Plugins](compiler-plugins.md)
|
||||
* [Inline Assembly](inline-assembly.md)
|
||||
* [No stdlib](no-stdlib.md)
|
||||
* [Intrinsics](intrinsics.md)
|
||||
* [Lang items](lang-items.md)
|
||||
* [Advanced linking](advanced-linking.md)
|
||||
* [Benchmark Tests](benchmark-tests.md)
|
||||
* [Box Syntax and Patterns](box-syntax-and-patterns.md)
|
||||
* [Slice Patterns](slice-patterns.md)
|
||||
* [Associated Constants](associated-constants.md)
|
||||
* [Custom Allocators](custom-allocators.md)
|
||||
* [Glossary](glossary.md)
|
||||
* [Syntax Index](syntax-index.md)
|
||||
* [Bibliography](bibliography.md)
|
||||
|
@ -1,145 +0,0 @@
|
||||
# Advanced Linking
|
||||
|
||||
The common cases of linking with Rust have been covered earlier in this book,
|
||||
but supporting the range of linking possibilities made available by other
|
||||
languages is important for Rust to achieve seamless interaction with native
|
||||
libraries.
|
||||
|
||||
# Link args
|
||||
|
||||
There is one other way to tell `rustc` how to customize linking, and that is via
|
||||
the `link_args` attribute. This attribute is applied to `extern` blocks and
|
||||
specifies raw flags which need to get passed to the linker when producing an
|
||||
artifact. An example usage would be:
|
||||
|
||||
```rust,no_run
|
||||
#![feature(link_args)]
|
||||
|
||||
#[link_args = "-foo -bar -baz"]
|
||||
extern {}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
Note that this feature is currently hidden behind the `feature(link_args)` gate
|
||||
because this is not a sanctioned way of performing linking. Right now `rustc`
|
||||
shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC),
|
||||
so it makes sense to provide extra command line
|
||||
arguments, but this will not always be the case. In the future `rustc` may use
|
||||
LLVM directly to link native libraries, in which case `link_args` will have no
|
||||
meaning. You can achieve the same effect as the `link_args` attribute with the
|
||||
`-C link-args` argument to `rustc`.
|
||||
|
||||
It is highly recommended to *not* use this attribute, and rather use the more
|
||||
formal `#[link(...)]` attribute on `extern` blocks instead.
|
||||
|
||||
# Static linking
|
||||
|
||||
Static linking refers to the process of creating output that contains all
|
||||
required libraries and so doesn't need libraries installed on every system where
|
||||
you want to use your compiled project. Pure-Rust dependencies are statically
|
||||
linked by default so you can use created binaries and libraries without
|
||||
installing Rust everywhere. By contrast, native libraries
|
||||
(e.g. `libc` and `libm`) are usually dynamically linked, but it is possible to
|
||||
change this and statically link them as well.
|
||||
|
||||
Linking is a very platform-dependent topic, and static linking may not even be
|
||||
possible on some platforms! This section assumes some basic familiarity with
|
||||
linking on your platform of choice.
|
||||
|
||||
## Linux
|
||||
|
||||
By default, all Rust programs on Linux will link to the system `libc` along with
|
||||
a number of other libraries. Let's look at an example on a 64-bit Linux machine
|
||||
with GCC and `glibc` (by far the most common `libc` on Linux):
|
||||
|
||||
```text
|
||||
$ cat example.rs
|
||||
fn main() {}
|
||||
$ rustc example.rs
|
||||
$ ldd example
|
||||
linux-vdso.so.1 => (0x00007ffd565fd000)
|
||||
libdl.so.2 => /lib/x86_64-linux-gnu/libdl.so.2 (0x00007fa81889c000)
|
||||
libpthread.so.0 => /lib/x86_64-linux-gnu/libpthread.so.0 (0x00007fa81867e000)
|
||||
librt.so.1 => /lib/x86_64-linux-gnu/librt.so.1 (0x00007fa818475000)
|
||||
libgcc_s.so.1 => /lib/x86_64-linux-gnu/libgcc_s.so.1 (0x00007fa81825f000)
|
||||
libc.so.6 => /lib/x86_64-linux-gnu/libc.so.6 (0x00007fa817e9a000)
|
||||
/lib64/ld-linux-x86-64.so.2 (0x00007fa818cf9000)
|
||||
libm.so.6 => /lib/x86_64-linux-gnu/libm.so.6 (0x00007fa817b93000)
|
||||
```
|
||||
|
||||
Dynamic linking on Linux can be undesirable if you wish to use new library
|
||||
features on old systems or target systems which do not have the required
|
||||
dependencies for your program to run.
|
||||
|
||||
Static linking is supported via an alternative `libc`, [`musl`](http://www.musl-libc.org). You can compile
|
||||
your own version of Rust with `musl` enabled and install it into a custom
|
||||
directory with the instructions below:
|
||||
|
||||
```text
|
||||
$ mkdir musldist
|
||||
$ PREFIX=$(pwd)/musldist
|
||||
$
|
||||
$ # Build musl
|
||||
$ curl -O http://www.musl-libc.org/releases/musl-1.1.10.tar.gz
|
||||
$ tar xf musl-1.1.10.tar.gz
|
||||
$ cd musl-1.1.10/
|
||||
musl-1.1.10 $ ./configure --disable-shared --prefix=$PREFIX
|
||||
musl-1.1.10 $ make
|
||||
musl-1.1.10 $ make install
|
||||
musl-1.1.10 $ cd ..
|
||||
$ du -h musldist/lib/libc.a
|
||||
2.2M musldist/lib/libc.a
|
||||
$
|
||||
$ # Build libunwind.a
|
||||
$ curl -O http://llvm.org/releases/3.7.0/llvm-3.7.0.src.tar.xz
|
||||
$ tar xf llvm-3.7.0.src.tar.xz
|
||||
$ cd llvm-3.7.0.src/projects/
|
||||
llvm-3.7.0.src/projects $ curl http://llvm.org/releases/3.7.0/libunwind-3.7.0.src.tar.xz | tar xJf -
|
||||
llvm-3.7.0.src/projects $ mv libunwind-3.7.0.src libunwind
|
||||
llvm-3.7.0.src/projects $ mkdir libunwind/build
|
||||
llvm-3.7.0.src/projects $ cd libunwind/build
|
||||
llvm-3.7.0.src/projects/libunwind/build $ cmake -DLLVM_PATH=../../.. -DLIBUNWIND_ENABLE_SHARED=0 ..
|
||||
llvm-3.7.0.src/projects/libunwind/build $ make
|
||||
llvm-3.7.0.src/projects/libunwind/build $ cp lib/libunwind.a $PREFIX/lib/
|
||||
llvm-3.7.0.src/projects/libunwind/build $ cd ../../../../
|
||||
$ du -h musldist/lib/libunwind.a
|
||||
164K musldist/lib/libunwind.a
|
||||
$
|
||||
$ # Build musl-enabled rust
|
||||
$ git clone https://github.com/rust-lang/rust.git muslrust
|
||||
$ cd muslrust
|
||||
muslrust $ ./configure --target=x86_64-unknown-linux-musl --musl-root=$PREFIX --prefix=$PREFIX
|
||||
muslrust $ make
|
||||
muslrust $ make install
|
||||
muslrust $ cd ..
|
||||
$ du -h musldist/bin/rustc
|
||||
12K musldist/bin/rustc
|
||||
```
|
||||
|
||||
You now have a build of a `musl`-enabled Rust! Because we've installed it to a
|
||||
custom prefix we need to make sure our system can find the binaries and appropriate
|
||||
libraries when we try and run it:
|
||||
|
||||
```text
|
||||
$ export PATH=$PREFIX/bin:$PATH
|
||||
$ export LD_LIBRARY_PATH=$PREFIX/lib:$LD_LIBRARY_PATH
|
||||
```
|
||||
|
||||
Let's try it out!
|
||||
|
||||
```text
|
||||
$ echo 'fn main() { println!("hi!"); panic!("failed"); }' > example.rs
|
||||
$ rustc --target=x86_64-unknown-linux-musl example.rs
|
||||
$ ldd example
|
||||
not a dynamic executable
|
||||
$ ./example
|
||||
hi!
|
||||
thread 'main' panicked at 'failed', example.rs:1
|
||||
```
|
||||
|
||||
Success! This binary can be copied to almost any Linux machine with the same
|
||||
machine architecture and run without issues.
|
||||
|
||||
`cargo build` also permits the `--target` option so you should be able to build
|
||||
your crates as normal. However, you may need to recompile your native libraries
|
||||
against `musl` before they can be linked against.
|
@ -1,79 +0,0 @@
|
||||
# Associated Constants
|
||||
|
||||
With the `associated_consts` feature, you can define constants like this:
|
||||
|
||||
```rust
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
const ID: i32;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, i32::ID);
|
||||
}
|
||||
```
|
||||
|
||||
Any implementor of `Foo` will have to define `ID`. Without the definition:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
const ID: i32;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
}
|
||||
```
|
||||
|
||||
gives
|
||||
|
||||
```text
|
||||
error: not all trait items implemented, missing: `ID` [E0046]
|
||||
impl Foo for i32 {
|
||||
}
|
||||
```
|
||||
|
||||
A default value can be implemented as well:
|
||||
|
||||
```rust
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
}
|
||||
|
||||
impl Foo for i64 {
|
||||
const ID: i32 = 5;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, i32::ID);
|
||||
assert_eq!(5, i64::ID);
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, when implementing `Foo`, you can leave it unimplemented, as
|
||||
with `i32`. It will then use the default value. But, as in `i64`, we can also
|
||||
add our own definition.
|
||||
|
||||
Associated constants don’t have to be associated with a trait. An `impl` block
|
||||
for a `struct` or an `enum` works fine too:
|
||||
|
||||
```rust
|
||||
#![feature(associated_consts)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
const FOO: u32 = 3;
|
||||
}
|
||||
```
|
@ -1,100 +0,0 @@
|
||||
# Box Syntax and Patterns
|
||||
|
||||
Currently the only stable way to create a `Box` is via the `Box::new` method.
|
||||
Also it is not possible in stable Rust to destructure a `Box` in a match
|
||||
pattern. The unstable `box` keyword can be used to both create and destructure
|
||||
a `Box`. An example usage would be:
|
||||
|
||||
```rust
|
||||
#![feature(box_syntax, box_patterns)]
|
||||
|
||||
fn main() {
|
||||
let b = Some(box 5);
|
||||
match b {
|
||||
Some(box n) if n < 0 => {
|
||||
println!("Box contains negative number {}", n);
|
||||
},
|
||||
Some(box n) if n >= 0 => {
|
||||
println!("Box contains non-negative number {}", n);
|
||||
},
|
||||
None => {
|
||||
println!("No box");
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that these features are currently hidden behind the `box_syntax` (box
|
||||
creation) and `box_patterns` (destructuring and pattern matching) gates
|
||||
because the syntax may still change in the future.
|
||||
|
||||
# Returning Pointers
|
||||
|
||||
In many languages with pointers, you'd return a pointer from a function
|
||||
so as to avoid copying a large data structure. For example:
|
||||
|
||||
```rust
|
||||
struct BigStruct {
|
||||
one: i32,
|
||||
two: i32,
|
||||
// Etc.
|
||||
one_hundred: i32,
|
||||
}
|
||||
|
||||
fn foo(x: Box<BigStruct>) -> Box<BigStruct> {
|
||||
Box::new(*x)
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Box::new(BigStruct {
|
||||
one: 1,
|
||||
two: 2,
|
||||
one_hundred: 100,
|
||||
});
|
||||
|
||||
let y = foo(x);
|
||||
}
|
||||
```
|
||||
|
||||
The idea is that by passing around a box, you're only copying a pointer, rather
|
||||
than the hundred `i32`s that make up the `BigStruct`.
|
||||
|
||||
This is an antipattern in Rust. Instead, write this:
|
||||
|
||||
```rust
|
||||
#![feature(box_syntax)]
|
||||
|
||||
struct BigStruct {
|
||||
one: i32,
|
||||
two: i32,
|
||||
// Etc.
|
||||
one_hundred: i32,
|
||||
}
|
||||
|
||||
fn foo(x: Box<BigStruct>) -> BigStruct {
|
||||
*x
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let x = Box::new(BigStruct {
|
||||
one: 1,
|
||||
two: 2,
|
||||
one_hundred: 100,
|
||||
});
|
||||
|
||||
let y: Box<BigStruct> = box foo(x);
|
||||
}
|
||||
```
|
||||
|
||||
This gives you flexibility without sacrificing performance.
|
||||
|
||||
You may think that this gives us terrible performance: return a value and then
|
||||
immediately box it up ?! Isn't this pattern the worst of both worlds? Rust is
|
||||
smarter than that. There is no copy in this code. `main` allocates enough room
|
||||
for the `box`, passes a pointer to that memory into `foo` as `x`, and then
|
||||
`foo` writes the value straight into the `Box<T>`.
|
||||
|
||||
This is important enough that it bears repeating: pointers are not for
|
||||
optimizing returning values from your code. Allow the caller to choose how they
|
||||
want to use your output.
|
@ -1,171 +0,0 @@
|
||||
# Custom Allocators
|
||||
|
||||
Allocating memory isn't always the easiest thing to do, and while Rust generally
|
||||
takes care of this by default it often becomes necessary to customize how
|
||||
allocation occurs. The compiler and standard library currently allow switching
|
||||
out the default global allocator in use at compile time. The design is currently
|
||||
spelled out in [RFC 1183][rfc] but this will walk you through how to get your
|
||||
own allocator up and running.
|
||||
|
||||
[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1183-swap-out-jemalloc.md
|
||||
|
||||
# Default Allocator
|
||||
|
||||
The compiler currently ships two default allocators: `alloc_system` and
|
||||
`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
|
||||
are normal Rust crates and contain an implementation of the routines to
|
||||
allocate and deallocate memory. The standard library is not compiled assuming
|
||||
either one, and the compiler will decide which allocator is in use at
|
||||
compile-time depending on the type of output artifact being produced.
|
||||
|
||||
Binaries generated by the compiler will use `alloc_jemalloc` by default (where
|
||||
available). In this situation the compiler "controls the world" in the sense of
|
||||
it has power over the final link. Primarily this means that the allocator
|
||||
decision can be left up the compiler.
|
||||
|
||||
Dynamic and static libraries, however, will use `alloc_system` by default. Here
|
||||
Rust is typically a 'guest' in another application or another world where it
|
||||
cannot authoritatively decide what allocator is in use. As a result it resorts
|
||||
back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
|
||||
memory.
|
||||
|
||||
# Switching Allocators
|
||||
|
||||
Although the compiler's default choices may work most of the time, it's often
|
||||
necessary to tweak certain aspects. Overriding the compiler's decision about
|
||||
which allocator is in use is done simply by linking to the desired allocator:
|
||||
|
||||
```rust,no_run
|
||||
#![feature(alloc_system)]
|
||||
|
||||
extern crate alloc_system;
|
||||
|
||||
fn main() {
|
||||
let a = Box::new(4); // Allocates from the system allocator.
|
||||
println!("{}", a);
|
||||
}
|
||||
```
|
||||
|
||||
In this example the binary generated will not link to jemalloc by default but
|
||||
instead use the system allocator. Conversely to generate a dynamic library which
|
||||
uses jemalloc by default one would write:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(alloc_jemalloc)]
|
||||
#![crate_type = "dylib"]
|
||||
|
||||
extern crate alloc_jemalloc;
|
||||
|
||||
pub fn foo() {
|
||||
let a = Box::new(4); // Allocates from jemalloc.
|
||||
println!("{}", a);
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
# Writing a custom allocator
|
||||
|
||||
Sometimes even the choices of jemalloc vs the system allocator aren't enough and
|
||||
an entirely new custom allocator is required. In this you'll write your own
|
||||
crate which implements the allocator API (e.g. the same as `alloc_system` or
|
||||
`alloc_jemalloc`). As an example, let's take a look at a simplified and
|
||||
annotated version of `alloc_system`
|
||||
|
||||
```rust,no_run
|
||||
# // Only needed for rustdoc --test down below.
|
||||
# #![feature(lang_items)]
|
||||
// The compiler needs to be instructed that this crate is an allocator in order
|
||||
// to realize that when this is linked in another allocator like jemalloc should
|
||||
// not be linked in.
|
||||
#![feature(allocator)]
|
||||
#![allocator]
|
||||
|
||||
// Allocators are not allowed to depend on the standard library which in turn
|
||||
// requires an allocator in order to avoid circular dependencies. This crate,
|
||||
// however, can use all of libcore.
|
||||
#![no_std]
|
||||
|
||||
// Let's give a unique name to our custom allocator:
|
||||
#![crate_name = "my_allocator"]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
// Our system allocator will use the in-tree libc crate for FFI bindings. Note
|
||||
// that currently the external (crates.io) libc cannot be used because it links
|
||||
// to the standard library (e.g. `#![no_std]` isn't stable yet), so that's why
|
||||
// this specifically requires the in-tree version.
|
||||
#![feature(libc)]
|
||||
extern crate libc;
|
||||
|
||||
// Listed below are the five allocation functions currently required by custom
|
||||
// allocators. Their signatures and symbol names are not currently typechecked
|
||||
// by the compiler, but this is a future extension and are required to match
|
||||
// what is found below.
|
||||
//
|
||||
// Note that the standard `malloc` and `realloc` functions do not provide a way
|
||||
// to communicate alignment so this implementation would need to be improved
|
||||
// with respect to alignment in that aspect.
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 {
|
||||
unsafe { libc::malloc(size as libc::size_t) as *mut u8 }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
|
||||
unsafe { libc::free(ptr as *mut libc::c_void) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
|
||||
_align: usize) -> *mut u8 {
|
||||
unsafe {
|
||||
libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize,
|
||||
_size: usize, _align: usize) -> usize {
|
||||
old_size // This api is not supported by libc.
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
|
||||
size
|
||||
}
|
||||
|
||||
# // Only needed to get rustdoc to test this:
|
||||
# fn main() {}
|
||||
# #[lang = "panic_fmt"] fn panic_fmt() {}
|
||||
# #[lang = "eh_personality"] fn eh_personality() {}
|
||||
# #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {}
|
||||
# #[no_mangle] pub extern fn rust_eh_register_frames () {}
|
||||
# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
|
||||
```
|
||||
|
||||
After we compile this crate, it can be used as follows:
|
||||
|
||||
```rust,ignore
|
||||
extern crate my_allocator;
|
||||
|
||||
fn main() {
|
||||
let a = Box::new(8); // Allocates memory via our custom allocator crate.
|
||||
println!("{}", a);
|
||||
}
|
||||
```
|
||||
|
||||
# Custom allocator limitations
|
||||
|
||||
There are a few restrictions when working with custom allocators which may cause
|
||||
compiler errors:
|
||||
|
||||
* Any one artifact may only be linked to at most one allocator. Binaries,
|
||||
dylibs, and staticlibs must link to exactly one allocator, and if none have
|
||||
been explicitly chosen the compiler will choose one. On the other hand rlibs
|
||||
do not need to link to an allocator (but still can).
|
||||
|
||||
* A consumer of an allocator is tagged with `#![needs_allocator]` (e.g. the
|
||||
`liballoc` crate currently) and an `#[allocator]` crate cannot transitively
|
||||
depend on a crate which needs an allocator (e.g. circular dependencies are not
|
||||
allowed). This basically means that allocators must restrict themselves to
|
||||
libcore currently.
|
@ -1,184 +0,0 @@
|
||||
# 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.
|
||||
|
||||
```rust,ignore
|
||||
asm!(assembly template
|
||||
: output operands
|
||||
: input operands
|
||||
: clobbers
|
||||
: options
|
||||
);
|
||||
```
|
||||
|
||||
Any use of `asm` is feature gated (requires `#![feature(asm)]` on the
|
||||
crate to allow) and of course requires an `unsafe` block.
|
||||
|
||||
> **Note**: the examples here are given in x86/x86-64 assembly, but
|
||||
> all platforms are supported.
|
||||
|
||||
## Assembly template
|
||||
|
||||
The `assembly template` is the only required parameter and must be a
|
||||
literal string (i.e. `""`)
|
||||
|
||||
```rust
|
||||
#![feature(asm)]
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn foo() {
|
||||
unsafe {
|
||||
asm!("NOP");
|
||||
}
|
||||
}
|
||||
|
||||
// Other platforms:
|
||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
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:
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
# fn main() { unsafe {
|
||||
asm!("xor %eax, %eax"
|
||||
:
|
||||
:
|
||||
: "eax"
|
||||
);
|
||||
# } }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
Whitespace also doesn't matter:
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
# fn main() { unsafe {
|
||||
asm!("xor %eax, %eax" ::: "eax");
|
||||
# } }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
## Operands
|
||||
|
||||
Input and output operands follow the same format: `:
|
||||
"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
|
||||
expressions must be mutable lvalues, or not yet assigned:
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn add(a: i32, b: i32) -> i32 {
|
||||
let c: i32;
|
||||
unsafe {
|
||||
asm!("add $2, $0"
|
||||
: "=r"(c)
|
||||
: "0"(a), "r"(b)
|
||||
);
|
||||
}
|
||||
c
|
||||
}
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn add(a: i32, b: i32) -> i32 { a + b }
|
||||
|
||||
fn main() {
|
||||
assert_eq!(add(3, 14159), 14162)
|
||||
}
|
||||
```
|
||||
|
||||
If you would like to use real operands in this position, however,
|
||||
you are required to put curly braces `{}` around the register that
|
||||
you want, and you are required to put the specific size of the
|
||||
operand. This is useful for very low level programming, where
|
||||
which register you use is important:
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
# unsafe fn read_byte_in(port: u16) -> u8 {
|
||||
let result: u8;
|
||||
asm!("in %dx, %al" : "={al}"(result) : "{dx}"(port));
|
||||
result
|
||||
# }
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
# fn main() { unsafe {
|
||||
// Put the value 0x200 in eax:
|
||||
asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
|
||||
# } }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
1. *volatile* - specifying this is analogous to
|
||||
`__asm__ __volatile__ (...)` in gcc/clang.
|
||||
2. *alignstack* - certain instructions expect the stack to be
|
||||
aligned a certain way (i.e. SSE) and specifying this indicates to
|
||||
the compiler to insert its usual stack alignment code
|
||||
3. *intel* - use intel syntax instead of the default AT&T.
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
# fn main() {
|
||||
let result: i32;
|
||||
unsafe {
|
||||
asm!("mov eax, 2" : "={eax}"(result) : : : "intel")
|
||||
}
|
||||
println!("eax is currently {}", result);
|
||||
# }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
## More Information
|
||||
|
||||
The current implementation of the `asm!` macro is a direct binding to [LLVM's
|
||||
inline assembler expressions][llvm-docs], so be sure to check out [their
|
||||
documentation as well][llvm-docs] for more information about clobbers,
|
||||
constraints, etc.
|
||||
|
||||
[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions
|
@ -1,25 +0,0 @@
|
||||
# Intrinsics
|
||||
|
||||
> **Note**: intrinsics will forever have an unstable interface, it is
|
||||
> recommended to use the stable interfaces of libcore rather than intrinsics
|
||||
> directly.
|
||||
|
||||
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
|
||||
|
||||
```rust
|
||||
#![feature(intrinsics)]
|
||||
# fn main() {}
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn transmute<T, U>(x: T) -> U;
|
||||
|
||||
fn offset<T>(dst: *const T, offset: isize) -> *const T;
|
||||
}
|
||||
```
|
||||
|
||||
As with any other FFI functions, these are always `unsafe` to call.
|
||||
|
@ -1,84 +0,0 @@
|
||||
# Lang items
|
||||
|
||||
> **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.
|
||||
|
||||
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'.
|
||||
|
||||
For example, `Box` pointers require two lang items, one for allocation
|
||||
and one for deallocation. A freestanding program that uses the `Box`
|
||||
sugar for dynamic allocations via `malloc` and `free`:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(lang_items, box_syntax, start, libc, core_intrinsics)]
|
||||
#![no_std]
|
||||
use core::intrinsics;
|
||||
|
||||
extern crate libc;
|
||||
|
||||
#[lang = "owned_box"]
|
||||
pub struct Box<T>(*mut T);
|
||||
|
||||
#[lang = "exchange_malloc"]
|
||||
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
|
||||
let p = libc::malloc(size as libc::size_t) as *mut u8;
|
||||
|
||||
// Check if `malloc` failed:
|
||||
if p as usize == 0 {
|
||||
intrinsics::abort();
|
||||
}
|
||||
|
||||
p
|
||||
}
|
||||
|
||||
#[lang = "exchange_free"]
|
||||
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
|
||||
libc::free(ptr as *mut libc::c_void)
|
||||
}
|
||||
|
||||
#[lang = "box_free"]
|
||||
unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
|
||||
deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr));
|
||||
}
|
||||
|
||||
#[start]
|
||||
fn main(argc: isize, argv: *const *const u8) -> isize {
|
||||
let x = box 1;
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"] extern fn rust_eh_personality() {}
|
||||
#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } }
|
||||
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
|
||||
# #[no_mangle] pub extern fn rust_eh_register_frames () {}
|
||||
# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
|
||||
```
|
||||
|
||||
Note the use of `abort`: the `exchange_malloc` lang item is assumed to
|
||||
return a valid pointer, and so needs to do the check internally.
|
||||
|
||||
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.
|
||||
- stack unwinding and general failure; the `eh_personality`,
|
||||
`eh_unwind_resume`, `fail` and `fail_bounds_checks` lang items.
|
||||
- the traits in `std::marker` used to indicate types of
|
||||
various kinds; lang items `send`, `sync` and `copy`.
|
||||
- the marker types and variance indicators found in
|
||||
`std::marker`; lang items `covariant_type`,
|
||||
`contravariant_lifetime`, etc.
|
||||
|
||||
Lang items are loaded lazily by the compiler; e.g. if one never uses
|
||||
`Box` then there is no need to define functions for `exchange_malloc`
|
||||
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.
|
@ -1,100 +0,0 @@
|
||||
# Nightly Rust
|
||||
|
||||
Rust provides three distribution channels for Rust: nightly, beta, and stable.
|
||||
Unstable features are only available on nightly Rust. For more details on this
|
||||
process, see [Stability as a deliverable][stability].
|
||||
|
||||
[stability]: http://blog.rust-lang.org/2014/10/30/Stability.html
|
||||
|
||||
To install nightly Rust, you can use [rustup.rs][rustup]:
|
||||
|
||||
[rustup]: https://rustup.rs
|
||||
|
||||
```bash
|
||||
$ curl https://sh.rustup.rs -sSf | sh
|
||||
$ rustup install nightly
|
||||
```
|
||||
|
||||
If you're concerned about the [potential insecurity][insecurity] of using `curl
|
||||
| sh`, please keep reading and see our disclaimer below. And feel free to
|
||||
use a two-step version of the installation and examine our installation script:
|
||||
|
||||
```bash
|
||||
$ curl https://sh.rustup.rs -sSf -o rustup.sh
|
||||
$ sh rustup.sh
|
||||
$ rustup install nightly
|
||||
```
|
||||
|
||||
[insecurity]: http://curlpipesh.tumblr.com
|
||||
|
||||
If you're on Windows, please download the [rustup installer][installer]
|
||||
and run it.
|
||||
|
||||
[installer]: https://win.rustup.rs
|
||||
|
||||
## Uninstalling
|
||||
|
||||
If you decide you don't want Rust anymore, we'll be a bit sad, but that's okay.
|
||||
Not every programming language is great for everyone. Just run the uninstall
|
||||
command:
|
||||
|
||||
```bash
|
||||
$ rustup self uninstall
|
||||
```
|
||||
|
||||
Some people, and somewhat rightfully so, get very upset when we tell you to
|
||||
`curl | sh`. Basically, when you do this, you are trusting that the good
|
||||
people who maintain Rust aren't going to hack your computer and do bad things.
|
||||
That's a good instinct! If you're one of those people, please check out the
|
||||
documentation on [building Rust from Source][from-source], or [the official
|
||||
binary downloads][install-page].
|
||||
|
||||
[from-source]: https://github.com/rust-lang/rust#building-from-source
|
||||
[install-page]: https://www.rust-lang.org/install.html
|
||||
|
||||
Oh, we should also mention the officially supported platforms:
|
||||
|
||||
* Windows (7+)
|
||||
* Linux (2.6.18 or later, various distributions), x86 and x86-64
|
||||
* OSX 10.7 (Lion) or greater, x86 and x86-64
|
||||
|
||||
We extensively test Rust on these platforms, and a few others, too, like
|
||||
Android. But these are the ones most likely to work, as they have the most
|
||||
testing.
|
||||
|
||||
Finally, a comment about Windows. Rust considers Windows to be a first-class
|
||||
platform upon release, but if we're honest, the Windows experience isn't as
|
||||
integrated as the Linux/OS X experience is. We're working on it! If anything
|
||||
does not work, it is a bug. Please let us know if that happens. Each and every
|
||||
commit is tested against Windows like any other platform.
|
||||
|
||||
If you've got Rust installed, you can open up a shell, and type this:
|
||||
|
||||
```bash
|
||||
$ rustc --version
|
||||
```
|
||||
|
||||
You should see the version number, commit hash, commit date and build date:
|
||||
|
||||
```bash
|
||||
rustc 1.0.0-nightly (f11f3e7ba 2015-01-04) (built 2015-01-06)
|
||||
```
|
||||
|
||||
If you did, Rust has been installed successfully! Congrats!
|
||||
|
||||
This installer also installs a copy of the documentation locally, so you can
|
||||
read it offline. On UNIX systems, `/usr/local/share/doc/rust` is the location.
|
||||
On Windows, it's in a `share/doc` directory, inside wherever you installed Rust
|
||||
to.
|
||||
|
||||
If not, there are a number of places where you can get help. The easiest is
|
||||
[the #rust IRC channel on irc.mozilla.org][irc], which you can access through
|
||||
[Mibbit][mibbit]. Click that link, and you'll be chatting with other Rustaceans
|
||||
(a silly nickname we call ourselves), and we can help you out. Other great
|
||||
resources include [the users forum][users], and [Stack Overflow][stackoverflow].
|
||||
|
||||
[irc]: irc://irc.mozilla.org/#rust
|
||||
[mibbit]: http://chat.mibbit.com/?server=irc.mozilla.org&channel=%23rust
|
||||
[users]: https://users.rust-lang.org/
|
||||
[stackoverflow]: http://stackoverflow.com/questions/tagged/rust
|
||||
|
@ -1,145 +0,0 @@
|
||||
# No stdlib
|
||||
|
||||
Rust’s standard library provides a lot of useful functionality, but assumes
|
||||
support for various features of its host system: threads, networking, heap
|
||||
allocation, and others. There are systems that do not have these features,
|
||||
however, and Rust can work with those too! To do so, we tell Rust that we
|
||||
don’t want to use the standard library via an attribute: `#![no_std]`.
|
||||
|
||||
> Note: This feature is technically stable, but there are some caveats. For
|
||||
> one, you can build a `#![no_std]` _library_ on stable, but not a _binary_.
|
||||
> For details on libraries without the standard library, see [the chapter on
|
||||
> `#![no_std]`](using-rust-without-the-standard-library.html)
|
||||
|
||||
Obviously there's more to life than just libraries: one can use
|
||||
`#[no_std]` with an executable.
|
||||
|
||||
### Using libc
|
||||
|
||||
In order to build a `#[no_std]` executable we will need libc as a dependency. We can specify
|
||||
this using our `Cargo.toml` file:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
libc = { version = "0.2.14", default-features = false }
|
||||
```
|
||||
|
||||
Note that the default features have been disabled. This is a critical step -
|
||||
**the default features of libc include the standard library and so must be
|
||||
disabled.**
|
||||
|
||||
### Writing an executable without stdlib
|
||||
|
||||
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
|
||||
in the same format as C:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(lang_items, core_intrinsics)]
|
||||
#![feature(start)]
|
||||
#![no_std]
|
||||
use core::intrinsics;
|
||||
|
||||
// Pull in the system libc library for what crt0.o likely requires.
|
||||
extern crate libc;
|
||||
|
||||
// Entry point for this program.
|
||||
#[start]
|
||||
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
// These functions are used by the compiler, but not
|
||||
// for a bare-bones hello world. These are normally
|
||||
// provided by libstd.
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_personality() {
|
||||
}
|
||||
|
||||
// This function may be needed based on the compilation target.
|
||||
#[lang = "eh_unwind_resume"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_unwind_resume() {
|
||||
}
|
||||
|
||||
#[lang = "panic_fmt"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
|
||||
_file: &'static str,
|
||||
_line: u32) -> ! {
|
||||
unsafe { intrinsics::abort() }
|
||||
}
|
||||
```
|
||||
|
||||
To override the compiler-inserted `main` shim, one has to disable it
|
||||
with `#![no_main]` and then create the appropriate symbol with the
|
||||
correct ABI and the correct name, which requires overriding the
|
||||
compiler's name mangling too:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(lang_items, core_intrinsics)]
|
||||
#![feature(start)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
use core::intrinsics;
|
||||
|
||||
// Pull in the system libc library for what crt0.o likely requires.
|
||||
extern crate libc;
|
||||
|
||||
// Entry point for this program.
|
||||
#[no_mangle] // ensure that this symbol is called `main` in the output
|
||||
pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
|
||||
0
|
||||
}
|
||||
|
||||
// These functions are used by the compiler, but not
|
||||
// for a bare-bones hello world. These are normally
|
||||
// provided by libstd.
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_personality() {
|
||||
}
|
||||
|
||||
// This function may be needed based on the compilation target.
|
||||
#[lang = "eh_unwind_resume"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_unwind_resume() {
|
||||
}
|
||||
|
||||
#[lang = "panic_fmt"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
|
||||
_file: &'static str,
|
||||
_line: u32) -> ! {
|
||||
unsafe { intrinsics::abort() }
|
||||
}
|
||||
```
|
||||
|
||||
## More about the language items
|
||||
|
||||
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 library, but without it you must define your own. These symbols
|
||||
are called "language items", and they each have an internal name, and then a
|
||||
signature that an implementation must conform to.
|
||||
|
||||
The first of these functions, `rust_eh_personality`, is used by the failure
|
||||
mechanisms of the compiler. This is often mapped to GCC's personality function
|
||||
(see the [libstd implementation][unwind] for more information), but crates
|
||||
which do not trigger a panic can be assured that this function is never
|
||||
called. The language item's name is `eh_personality`.
|
||||
|
||||
[unwind]: https://github.com/rust-lang/rust/blob/master/src/libpanic_unwind/gcc.rs
|
||||
|
||||
The second function, `rust_begin_panic`, is also used by the failure mechanisms of the
|
||||
compiler. When a panic happens, this controls the message that's displayed on
|
||||
the screen. While the language item's name is `panic_fmt`, the symbol name is
|
||||
`rust_begin_panic`.
|
||||
|
||||
A third function, `rust_eh_unwind_resume`, is also needed if the `custom_unwind_resume`
|
||||
flag is set in the options of the compilation target. It allows customizing the
|
||||
process of resuming unwind at the end of the landing pads. The language item's name
|
||||
is `eh_unwind_resume`.
|
@ -1,42 +0,0 @@
|
||||
# Slice patterns
|
||||
|
||||
If you want to match against a slice or array, you can use `&` with the
|
||||
`slice_patterns` feature:
|
||||
|
||||
```rust
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn main() {
|
||||
let v = vec!["match_this", "1"];
|
||||
|
||||
match &v[..] {
|
||||
&["match_this", second] => println!("The second element is {}", second),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
The `advanced_slice_patterns` gate lets you use `..` to indicate any number of
|
||||
elements inside a pattern matching a slice. This wildcard can only be used once
|
||||
for a given array. If there's an identifier before the `..`, the result of the
|
||||
slice will be bound to that name. For example:
|
||||
|
||||
```rust
|
||||
#![feature(advanced_slice_patterns, slice_patterns)]
|
||||
|
||||
fn is_symmetric(list: &[u32]) -> bool {
|
||||
match list {
|
||||
&[] | &[_] => true,
|
||||
&[x, ref inside.., y] if x == y => is_symmetric(inside),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let sym = &[0, 1, 4, 2, 4, 1, 0];
|
||||
assert!(is_symmetric(sym));
|
||||
|
||||
let not_sym = &[0, 1, 7, 2, 4, 1, 0];
|
||||
assert!(!is_symmetric(not_sym));
|
||||
}
|
||||
```
|
@ -1,6 +1,9 @@
|
||||
[The Unstable Book](the-unstable-book.md)
|
||||
|
||||
- [asm](asm.md)
|
||||
- [alloc_system](alloc-system.md)
|
||||
- [alloc_jemalloc](alloc-jemalloc.md)
|
||||
- [test](test.md)
|
||||
- [concat_idents](concat-idents.md)
|
||||
- [link_args](link-args.md)
|
||||
- [log_syntax](log-syntax.md)
|
||||
|
@ -3,3 +3,5 @@
|
||||
The tracking issue for this feature is: [#38487]
|
||||
|
||||
[#38487]: https://github.com/rust-lang/rust/issues/38487
|
||||
|
||||
------------------------
|
||||
|
@ -2,3 +2,4 @@
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
@ -4,5 +4,4 @@ The tracking issue for this feature is: [#36167]
|
||||
|
||||
[#36167]: https://github.com/rust-lang/rust/issues/36167
|
||||
|
||||
|
||||
|
||||
------------------------
|
||||
|
@ -2,3 +2,5 @@
|
||||
|
||||
The tracking issue for this feature is: none.
|
||||
|
||||
------------------------
|
||||
|
||||
|
@ -2,4 +2,6 @@
|
||||
|
||||
The tracking issue for this feature is: none.
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
@ -4,5 +4,32 @@ The tracking issue for this feature is: [#23121]
|
||||
|
||||
[#23121]: https://github.com/rust-lang/rust/issues/23121
|
||||
|
||||
See also [`slice_patterns`](slice-patterns.html).
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
The `advanced_slice_patterns` gate lets you use `..` to indicate any number of
|
||||
elements inside a pattern matching a slice. This wildcard can only be used once
|
||||
for a given array. If there's an identifier before the `..`, the result of the
|
||||
slice will be bound to that name. For example:
|
||||
|
||||
```rust
|
||||
#![feature(advanced_slice_patterns, slice_patterns)]
|
||||
|
||||
fn is_symmetric(list: &[u32]) -> bool {
|
||||
match list {
|
||||
&[] | &[_] => true,
|
||||
&[x, ref inside.., y] if x == y => is_symmetric(inside),
|
||||
_ => false
|
||||
}
|
||||
}
|
||||
|
||||
fn main() {
|
||||
let sym = &[0, 1, 4, 2, 4, 1, 0];
|
||||
assert!(is_symmetric(sym));
|
||||
|
||||
let not_sym = &[0, 1, 7, 2, 4, 1, 0];
|
||||
assert!(!is_symmetric(not_sym));
|
||||
}
|
||||
```
|
||||
|
62
src/doc/unstable-book/src/alloc-jemalloc.md
Normal file
62
src/doc/unstable-book/src/alloc-jemalloc.md
Normal file
@ -0,0 +1,62 @@
|
||||
# `alloc_jemalloc`
|
||||
|
||||
The tracking issue for this feature is: [#33082]
|
||||
|
||||
[#33082]: https://github.com/rust-lang/rust/issues/33082
|
||||
|
||||
See also [`alloc_system`](alloc-system.md).
|
||||
|
||||
------------------------
|
||||
|
||||
The compiler currently ships two default allocators: `alloc_system` and
|
||||
`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
|
||||
are normal Rust crates and contain an implementation of the routines to
|
||||
allocate and deallocate memory. The standard library is not compiled assuming
|
||||
either one, and the compiler will decide which allocator is in use at
|
||||
compile-time depending on the type of output artifact being produced.
|
||||
|
||||
Binaries generated by the compiler will use `alloc_jemalloc` by default (where
|
||||
available). In this situation the compiler "controls the world" in the sense of
|
||||
it has power over the final link. Primarily this means that the allocator
|
||||
decision can be left up the compiler.
|
||||
|
||||
Dynamic and static libraries, however, will use `alloc_system` by default. Here
|
||||
Rust is typically a 'guest' in another application or another world where it
|
||||
cannot authoritatively decide what allocator is in use. As a result it resorts
|
||||
back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
|
||||
memory.
|
||||
|
||||
# Switching Allocators
|
||||
|
||||
Although the compiler's default choices may work most of the time, it's often
|
||||
necessary to tweak certain aspects. Overriding the compiler's decision about
|
||||
which allocator is in use is done simply by linking to the desired allocator:
|
||||
|
||||
```rust,no_run
|
||||
#![feature(alloc_system)]
|
||||
|
||||
extern crate alloc_system;
|
||||
|
||||
fn main() {
|
||||
let a = Box::new(4); // Allocates from the system allocator.
|
||||
println!("{}", a);
|
||||
}
|
||||
```
|
||||
|
||||
In this example the binary generated will not link to jemalloc by default but
|
||||
instead use the system allocator. Conversely to generate a dynamic library which
|
||||
uses jemalloc by default one would write:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(alloc_jemalloc)]
|
||||
#![crate_type = "dylib"]
|
||||
|
||||
extern crate alloc_jemalloc;
|
||||
|
||||
pub fn foo() {
|
||||
let a = Box::new(4); // Allocates from jemalloc.
|
||||
println!("{}", a);
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
62
src/doc/unstable-book/src/alloc-system.md
Normal file
62
src/doc/unstable-book/src/alloc-system.md
Normal file
@ -0,0 +1,62 @@
|
||||
# `alloc_system`
|
||||
|
||||
The tracking issue for this feature is: [#33082]
|
||||
|
||||
[#33082]: https://github.com/rust-lang/rust/issues/33082
|
||||
|
||||
See also [`alloc_jemalloc`](alloc-jemalloc.md).
|
||||
|
||||
------------------------
|
||||
|
||||
The compiler currently ships two default allocators: `alloc_system` and
|
||||
`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
|
||||
are normal Rust crates and contain an implementation of the routines to
|
||||
allocate and deallocate memory. The standard library is not compiled assuming
|
||||
either one, and the compiler will decide which allocator is in use at
|
||||
compile-time depending on the type of output artifact being produced.
|
||||
|
||||
Binaries generated by the compiler will use `alloc_jemalloc` by default (where
|
||||
available). In this situation the compiler "controls the world" in the sense of
|
||||
it has power over the final link. Primarily this means that the allocator
|
||||
decision can be left up the compiler.
|
||||
|
||||
Dynamic and static libraries, however, will use `alloc_system` by default. Here
|
||||
Rust is typically a 'guest' in another application or another world where it
|
||||
cannot authoritatively decide what allocator is in use. As a result it resorts
|
||||
back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
|
||||
memory.
|
||||
|
||||
# Switching Allocators
|
||||
|
||||
Although the compiler's default choices may work most of the time, it's often
|
||||
necessary to tweak certain aspects. Overriding the compiler's decision about
|
||||
which allocator is in use is done simply by linking to the desired allocator:
|
||||
|
||||
```rust,no_run
|
||||
#![feature(alloc_system)]
|
||||
|
||||
extern crate alloc_system;
|
||||
|
||||
fn main() {
|
||||
let a = Box::new(4); // Allocates from the system allocator.
|
||||
println!("{}", a);
|
||||
}
|
||||
```
|
||||
|
||||
In this example the binary generated will not link to jemalloc by default but
|
||||
instead use the system allocator. Conversely to generate a dynamic library which
|
||||
uses jemalloc by default one would write:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(alloc_jemalloc)]
|
||||
#![crate_type = "dylib"]
|
||||
|
||||
extern crate alloc_jemalloc;
|
||||
|
||||
pub fn foo() {
|
||||
let a = Box::new(4); // Allocates from jemalloc.
|
||||
println!("{}", a);
|
||||
}
|
||||
# fn main() {}
|
||||
```
|
||||
|
@ -4,5 +4,111 @@ The tracking issue for this feature is: [#27389]
|
||||
|
||||
[#27389]: https://github.com/rust-lang/rust/issues/27389
|
||||
|
||||
------------------------
|
||||
|
||||
Sometimes even the choices of jemalloc vs the system allocator aren't enough and
|
||||
an entirely new custom allocator is required. In this you'll write your own
|
||||
crate which implements the allocator API (e.g. the same as `alloc_system` or
|
||||
`alloc_jemalloc`). As an example, let's take a look at a simplified and
|
||||
annotated version of `alloc_system`
|
||||
|
||||
```rust,no_run
|
||||
# // Only needed for rustdoc --test down below.
|
||||
# #![feature(lang_items)]
|
||||
// The compiler needs to be instructed that this crate is an allocator in order
|
||||
// to realize that when this is linked in another allocator like jemalloc should
|
||||
// not be linked in.
|
||||
#![feature(allocator)]
|
||||
#![allocator]
|
||||
|
||||
// Allocators are not allowed to depend on the standard library which in turn
|
||||
// requires an allocator in order to avoid circular dependencies. This crate,
|
||||
// however, can use all of libcore.
|
||||
#![no_std]
|
||||
|
||||
// Let's give a unique name to our custom allocator:
|
||||
#![crate_name = "my_allocator"]
|
||||
#![crate_type = "rlib"]
|
||||
|
||||
// Our system allocator will use the in-tree libc crate for FFI bindings. Note
|
||||
// that currently the external (crates.io) libc cannot be used because it links
|
||||
// to the standard library (e.g. `#![no_std]` isn't stable yet), so that's why
|
||||
// this specifically requires the in-tree version.
|
||||
#![feature(libc)]
|
||||
extern crate libc;
|
||||
|
||||
// Listed below are the five allocation functions currently required by custom
|
||||
// allocators. Their signatures and symbol names are not currently typechecked
|
||||
// by the compiler, but this is a future extension and are required to match
|
||||
// what is found below.
|
||||
//
|
||||
// Note that the standard `malloc` and `realloc` functions do not provide a way
|
||||
// to communicate alignment so this implementation would need to be improved
|
||||
// with respect to alignment in that aspect.
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 {
|
||||
unsafe { libc::malloc(size as libc::size_t) as *mut u8 }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
|
||||
unsafe { libc::free(ptr as *mut libc::c_void) }
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
|
||||
_align: usize) -> *mut u8 {
|
||||
unsafe {
|
||||
libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
|
||||
}
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize,
|
||||
_size: usize, _align: usize) -> usize {
|
||||
old_size // This api is not supported by libc.
|
||||
}
|
||||
|
||||
#[no_mangle]
|
||||
pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
|
||||
size
|
||||
}
|
||||
|
||||
# // Only needed to get rustdoc to test this:
|
||||
# fn main() {}
|
||||
# #[lang = "panic_fmt"] fn panic_fmt() {}
|
||||
# #[lang = "eh_personality"] fn eh_personality() {}
|
||||
# #[lang = "eh_unwind_resume"] extern fn eh_unwind_resume() {}
|
||||
# #[no_mangle] pub extern fn rust_eh_register_frames () {}
|
||||
# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
|
||||
```
|
||||
|
||||
After we compile this crate, it can be used as follows:
|
||||
|
||||
```rust,ignore
|
||||
extern crate my_allocator;
|
||||
|
||||
fn main() {
|
||||
let a = Box::new(8); // Allocates memory via our custom allocator crate.
|
||||
println!("{}", a);
|
||||
}
|
||||
```
|
||||
|
||||
## Custom allocator limitations
|
||||
|
||||
There are a few restrictions when working with custom allocators which may cause
|
||||
compiler errors:
|
||||
|
||||
* Any one artifact may only be linked to at most one allocator. Binaries,
|
||||
dylibs, and staticlibs must link to exactly one allocator, and if none have
|
||||
been explicitly chosen the compiler will choose one. On the other hand rlibs
|
||||
do not need to link to an allocator (but still can).
|
||||
|
||||
* A consumer of an allocator is tagged with `#![needs_allocator]` (e.g. the
|
||||
`liballoc` crate currently) and an `#[allocator]` crate cannot transitively
|
||||
depend on a crate which needs an allocator (e.g. circular dependencies are not
|
||||
allowed). This basically means that allocators must restrict themselves to
|
||||
libcore currently.
|
||||
|
||||
|
||||
|
@ -2,3 +2,5 @@
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
||||
|
@ -4,5 +4,188 @@ The tracking issue for this feature is: [#29722]
|
||||
|
||||
[#29722]: https://github.com/rust-lang/rust/issues/29722
|
||||
|
||||
------------------------
|
||||
|
||||
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.
|
||||
|
||||
```rust,ignore
|
||||
asm!(assembly template
|
||||
: output operands
|
||||
: input operands
|
||||
: clobbers
|
||||
: options
|
||||
);
|
||||
```
|
||||
|
||||
Any use of `asm` is feature gated (requires `#![feature(asm)]` on the
|
||||
crate to allow) and of course requires an `unsafe` block.
|
||||
|
||||
> **Note**: the examples here are given in x86/x86-64 assembly, but
|
||||
> all platforms are supported.
|
||||
|
||||
## Assembly template
|
||||
|
||||
The `assembly template` is the only required parameter and must be a
|
||||
literal string (i.e. `""`)
|
||||
|
||||
```rust
|
||||
#![feature(asm)]
|
||||
|
||||
#[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn foo() {
|
||||
unsafe {
|
||||
asm!("NOP");
|
||||
}
|
||||
}
|
||||
|
||||
// Other platforms:
|
||||
#[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
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:
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
# fn main() { unsafe {
|
||||
asm!("xor %eax, %eax"
|
||||
:
|
||||
:
|
||||
: "eax"
|
||||
);
|
||||
# } }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
Whitespace also doesn't matter:
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
# fn main() { unsafe {
|
||||
asm!("xor %eax, %eax" ::: "eax");
|
||||
# } }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
## Operands
|
||||
|
||||
Input and output operands follow the same format: `:
|
||||
"constraints1"(expr1), "constraints2"(expr2), ..."`. Output operand
|
||||
expressions must be mutable lvalues, or not yet assigned:
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
fn add(a: i32, b: i32) -> i32 {
|
||||
let c: i32;
|
||||
unsafe {
|
||||
asm!("add $2, $0"
|
||||
: "=r"(c)
|
||||
: "0"(a), "r"(b)
|
||||
);
|
||||
}
|
||||
c
|
||||
}
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn add(a: i32, b: i32) -> i32 { a + b }
|
||||
|
||||
fn main() {
|
||||
assert_eq!(add(3, 14159), 14162)
|
||||
}
|
||||
```
|
||||
|
||||
If you would like to use real operands in this position, however,
|
||||
you are required to put curly braces `{}` around the register that
|
||||
you want, and you are required to put the specific size of the
|
||||
operand. This is useful for very low level programming, where
|
||||
which register you use is important:
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
# unsafe fn read_byte_in(port: u16) -> u8 {
|
||||
let result: u8;
|
||||
asm!("in %dx, %al" : "={al}"(result) : "{dx}"(port));
|
||||
result
|
||||
# }
|
||||
```
|
||||
|
||||
## 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.
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
# fn main() { unsafe {
|
||||
// Put the value 0x200 in eax:
|
||||
asm!("mov $$0x200, %eax" : /* no outputs */ : /* no inputs */ : "eax");
|
||||
# } }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
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:
|
||||
|
||||
1. *volatile* - specifying this is analogous to
|
||||
`__asm__ __volatile__ (...)` in gcc/clang.
|
||||
2. *alignstack* - certain instructions expect the stack to be
|
||||
aligned a certain way (i.e. SSE) and specifying this indicates to
|
||||
the compiler to insert its usual stack alignment code
|
||||
3. *intel* - use intel syntax instead of the default AT&T.
|
||||
|
||||
```rust
|
||||
# #![feature(asm)]
|
||||
# #[cfg(any(target_arch = "x86", target_arch = "x86_64"))]
|
||||
# fn main() {
|
||||
let result: i32;
|
||||
unsafe {
|
||||
asm!("mov eax, 2" : "={eax}"(result) : : : "intel")
|
||||
}
|
||||
println!("eax is currently {}", result);
|
||||
# }
|
||||
# #[cfg(not(any(target_arch = "x86", target_arch = "x86_64")))]
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
## More Information
|
||||
|
||||
The current implementation of the `asm!` macro is a direct binding to [LLVM's
|
||||
inline assembler expressions][llvm-docs], so be sure to check out [their
|
||||
documentation as well][llvm-docs] for more information about clobbers,
|
||||
constraints, etc.
|
||||
|
||||
[llvm-docs]: http://llvm.org/docs/LangRef.html#inline-assembler-expressions
|
||||
|
||||
|
@ -4,5 +4,82 @@ The tracking issue for this feature is: [#29646]
|
||||
|
||||
[#29646]: https://github.com/rust-lang/rust/issues/29646
|
||||
|
||||
------------------------
|
||||
|
||||
With the `associated_consts` feature, you can define constants like this:
|
||||
|
||||
```rust
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
const ID: i32;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, i32::ID);
|
||||
}
|
||||
```
|
||||
|
||||
Any implementor of `Foo` will have to define `ID`. Without the definition:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
const ID: i32;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
}
|
||||
```
|
||||
|
||||
gives
|
||||
|
||||
```text
|
||||
error: not all trait items implemented, missing: `ID` [E0046]
|
||||
impl Foo for i32 {
|
||||
}
|
||||
```
|
||||
|
||||
A default value can be implemented as well:
|
||||
|
||||
```rust
|
||||
#![feature(associated_consts)]
|
||||
|
||||
trait Foo {
|
||||
const ID: i32 = 1;
|
||||
}
|
||||
|
||||
impl Foo for i32 {
|
||||
}
|
||||
|
||||
impl Foo for i64 {
|
||||
const ID: i32 = 5;
|
||||
}
|
||||
|
||||
fn main() {
|
||||
assert_eq!(1, i32::ID);
|
||||
assert_eq!(5, i64::ID);
|
||||
}
|
||||
```
|
||||
|
||||
As you can see, when implementing `Foo`, you can leave it unimplemented, as
|
||||
with `i32`. It will then use the default value. But, as in `i64`, we can also
|
||||
add our own definition.
|
||||
|
||||
Associated constants don’t have to be associated with a trait. An `impl` block
|
||||
for a `struct` or an `enum` works fine too:
|
||||
|
||||
```rust
|
||||
#![feature(associated_consts)]
|
||||
|
||||
struct Foo;
|
||||
|
||||
impl Foo {
|
||||
const FOO: u32 = 3;
|
||||
}
|
||||
```
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29661]
|
||||
|
||||
[#29661]: https://github.com/rust-lang/rust/issues/29661
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#34981]
|
||||
|
||||
[#34981]: https://github.com/rust-lang/rust/issues/34981
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,29 @@ The tracking issue for this feature is: [#29641]
|
||||
|
||||
[#29641]: https://github.com/rust-lang/rust/issues/29641
|
||||
|
||||
See also [`box_syntax`](box-syntax.html)
|
||||
|
||||
------------------------
|
||||
|
||||
Box patterns let you match on `Box<T>`s:
|
||||
|
||||
|
||||
```rust
|
||||
#![feature(box_patterns)]
|
||||
|
||||
fn main() {
|
||||
let b = Some(Box::new(5));
|
||||
match b {
|
||||
Some(box n) if n < 0 => {
|
||||
println!("Box contains negative number {}", n);
|
||||
},
|
||||
Some(box n) if n >= 0 => {
|
||||
println!("Box contains non-negative number {}", n);
|
||||
},
|
||||
None => {
|
||||
println!("No box");
|
||||
},
|
||||
_ => unreachable!()
|
||||
}
|
||||
}
|
||||
```
|
||||
|
@ -4,5 +4,19 @@ The tracking issue for this feature is: [#27779]
|
||||
|
||||
[#27779]: https://github.com/rust-lang/rust/issues/27779
|
||||
|
||||
See also [`box_patterns`](box-patterns.html)
|
||||
|
||||
------------------------
|
||||
|
||||
Currently the only stable way to create a `Box` is via the `Box::new` method.
|
||||
Also it is not possible in stable Rust to destructure a `Box` in a match
|
||||
pattern. The unstable `box` keyword can be used to create a `Box`. An example
|
||||
usage would be:
|
||||
|
||||
```rust
|
||||
#![feature(box_syntax)]
|
||||
|
||||
fn main() {
|
||||
let b = box 5;
|
||||
}
|
||||
```
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29717]
|
||||
|
||||
[#29717]: https://github.com/rust-lang/rust/issues/29717
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#32976]
|
||||
|
||||
[#32976]: https://github.com/rust-lang/rust/issues/32976
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29594]
|
||||
|
||||
[#29594]: https://github.com/rust-lang/rust/issues/29594
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29717]
|
||||
|
||||
[#29717]: https://github.com/rust-lang/rust/issues/29717
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -2,3 +2,5 @@
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29599]
|
||||
|
||||
[#29599]: https://github.com/rust-lang/rust/issues/29599
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#34511]
|
||||
|
||||
[#34511]: https://github.com/rust-lang/rust/issues/34511
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#24111]
|
||||
|
||||
[#24111]: https://github.com/rust-lang/rust/issues/24111
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29947]
|
||||
|
||||
[#29947]: https://github.com/rust-lang/rust/issues/29947
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29642]
|
||||
|
||||
[#29642]: https://github.com/rust-lang/rust/issues/29642
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29644]
|
||||
|
||||
[#29644]: https://github.com/rust-lang/rust/issues/29644
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#27336]
|
||||
|
||||
[#27336]: https://github.com/rust-lang/rust/issues/27336
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#33156]
|
||||
|
||||
[#33156]: https://github.com/rust-lang/rust/issues/33156
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#34761]
|
||||
|
||||
[#34761]: https://github.com/rust-lang/rust/issues/34761
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#28498]
|
||||
|
||||
[#28498]: https://github.com/rust-lang/rust/issues/28498
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#37854]
|
||||
|
||||
[#37854]: https://github.com/rust-lang/rust/issues/37854
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#37340]
|
||||
|
||||
[#37340]: https://github.com/rust-lang/rust/issues/37340
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29635]
|
||||
|
||||
[#29635]: https://github.com/rust-lang/rust/issues/29635
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#34761]
|
||||
|
||||
[#34761]: https://github.com/rust-lang/rust/issues/34761
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#35118]
|
||||
|
||||
[#35118]: https://github.com/rust-lang/rust/issues/35118
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#28237]
|
||||
|
||||
[#28237]: https://github.com/rust-lang/rust/issues/28237
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -1,3 +1,30 @@
|
||||
# `intrinsics`
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
Intrinsics are never intended to be stable directly, but intrinsics are often
|
||||
exported in some sort of stable manner. Prefer using the stable interfaces to
|
||||
the intrinsic directly when you can.
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
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
|
||||
|
||||
```rust
|
||||
#![feature(intrinsics)]
|
||||
# fn main() {}
|
||||
|
||||
extern "rust-intrinsic" {
|
||||
fn transmute<T, U>(x: T) -> U;
|
||||
|
||||
fn offset<T>(dst: *const T, offset: isize) -> *const T;
|
||||
}
|
||||
```
|
||||
|
||||
As with any other FFI functions, these are always `unsafe` to call.
|
||||
|
||||
|
@ -2,3 +2,218 @@
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
||||
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'.
|
||||
|
||||
For example, `Box` pointers require two lang items, one for allocation
|
||||
and one for deallocation. A freestanding program that uses the `Box`
|
||||
sugar for dynamic allocations via `malloc` and `free`:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(lang_items, box_syntax, start, libc, core_intrinsics)]
|
||||
#![no_std]
|
||||
use core::intrinsics;
|
||||
|
||||
extern crate libc;
|
||||
|
||||
#[lang = "owned_box"]
|
||||
pub struct Box<T>(*mut T);
|
||||
|
||||
#[lang = "exchange_malloc"]
|
||||
unsafe fn allocate(size: usize, _align: usize) -> *mut u8 {
|
||||
let p = libc::malloc(size as libc::size_t) as *mut u8;
|
||||
|
||||
// Check if `malloc` failed:
|
||||
if p as usize == 0 {
|
||||
intrinsics::abort();
|
||||
}
|
||||
|
||||
p
|
||||
}
|
||||
|
||||
#[lang = "exchange_free"]
|
||||
unsafe fn deallocate(ptr: *mut u8, _size: usize, _align: usize) {
|
||||
libc::free(ptr as *mut libc::c_void)
|
||||
}
|
||||
|
||||
#[lang = "box_free"]
|
||||
unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
|
||||
deallocate(ptr as *mut u8, ::core::mem::size_of_val(&*ptr), ::core::mem::align_of_val(&*ptr));
|
||||
}
|
||||
|
||||
#[start]
|
||||
fn main(argc: isize, argv: *const *const u8) -> isize {
|
||||
let x = box 1;
|
||||
|
||||
0
|
||||
}
|
||||
|
||||
#[lang = "eh_personality"] extern fn rust_eh_personality() {}
|
||||
#[lang = "panic_fmt"] extern fn rust_begin_panic() -> ! { unsafe { intrinsics::abort() } }
|
||||
# #[lang = "eh_unwind_resume"] extern fn rust_eh_unwind_resume() {}
|
||||
# #[no_mangle] pub extern fn rust_eh_register_frames () {}
|
||||
# #[no_mangle] pub extern fn rust_eh_unregister_frames () {}
|
||||
```
|
||||
|
||||
Note the use of `abort`: the `exchange_malloc` lang item is assumed to
|
||||
return a valid pointer, and so needs to do the check internally.
|
||||
|
||||
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.
|
||||
- stack unwinding and general failure; the `eh_personality`,
|
||||
`eh_unwind_resume`, `fail` and `fail_bounds_checks` lang items.
|
||||
- the traits in `std::marker` used to indicate types of
|
||||
various kinds; lang items `send`, `sync` and `copy`.
|
||||
- the marker types and variance indicators found in
|
||||
`std::marker`; lang items `covariant_type`,
|
||||
`contravariant_lifetime`, etc.
|
||||
|
||||
Lang items are loaded lazily by the compiler; e.g. if one never uses
|
||||
`Box` then there is no need to define functions for `exchange_malloc`
|
||||
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.
|
||||
|
||||
Most lang items are defined by `libcore`, but if you're trying to build
|
||||
an executable without the standard library, you'll run into the need
|
||||
for lang items. The rest of this page focuses on this use-case, even though
|
||||
lang items are a bit broader than that.
|
||||
|
||||
### Using libc
|
||||
|
||||
In order to build a `#[no_std]` executable we will need libc as a dependency.
|
||||
We can specify this using our `Cargo.toml` file:
|
||||
|
||||
```toml
|
||||
[dependencies]
|
||||
libc = { version = "0.2.14", default-features = false }
|
||||
```
|
||||
|
||||
Note that the default features have been disabled. This is a critical step -
|
||||
**the default features of libc include the standard library and so must be
|
||||
disabled.**
|
||||
|
||||
### Writing an executable without stdlib
|
||||
|
||||
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
|
||||
in the same format as C:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(lang_items, core_intrinsics)]
|
||||
#![feature(start)]
|
||||
#![no_std]
|
||||
use core::intrinsics;
|
||||
|
||||
// Pull in the system libc library for what crt0.o likely requires.
|
||||
extern crate libc;
|
||||
|
||||
// Entry point for this program.
|
||||
#[start]
|
||||
fn start(_argc: isize, _argv: *const *const u8) -> isize {
|
||||
0
|
||||
}
|
||||
|
||||
// These functions are used by the compiler, but not
|
||||
// for a bare-bones hello world. These are normally
|
||||
// provided by libstd.
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_personality() {
|
||||
}
|
||||
|
||||
// This function may be needed based on the compilation target.
|
||||
#[lang = "eh_unwind_resume"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_unwind_resume() {
|
||||
}
|
||||
|
||||
#[lang = "panic_fmt"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
|
||||
_file: &'static str,
|
||||
_line: u32) -> ! {
|
||||
unsafe { intrinsics::abort() }
|
||||
}
|
||||
```
|
||||
|
||||
To override the compiler-inserted `main` shim, one has to disable it
|
||||
with `#![no_main]` and then create the appropriate symbol with the
|
||||
correct ABI and the correct name, which requires overriding the
|
||||
compiler's name mangling too:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(lang_items, core_intrinsics)]
|
||||
#![feature(start)]
|
||||
#![no_std]
|
||||
#![no_main]
|
||||
use core::intrinsics;
|
||||
|
||||
// Pull in the system libc library for what crt0.o likely requires.
|
||||
extern crate libc;
|
||||
|
||||
// Entry point for this program.
|
||||
#[no_mangle] // ensure that this symbol is called `main` in the output
|
||||
pub extern fn main(_argc: i32, _argv: *const *const u8) -> i32 {
|
||||
0
|
||||
}
|
||||
|
||||
// These functions are used by the compiler, but not
|
||||
// for a bare-bones hello world. These are normally
|
||||
// provided by libstd.
|
||||
#[lang = "eh_personality"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_personality() {
|
||||
}
|
||||
|
||||
// This function may be needed based on the compilation target.
|
||||
#[lang = "eh_unwind_resume"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_eh_unwind_resume() {
|
||||
}
|
||||
|
||||
#[lang = "panic_fmt"]
|
||||
#[no_mangle]
|
||||
pub extern fn rust_begin_panic(_msg: core::fmt::Arguments,
|
||||
_file: &'static str,
|
||||
_line: u32) -> ! {
|
||||
unsafe { intrinsics::abort() }
|
||||
}
|
||||
```
|
||||
|
||||
## More about the language items
|
||||
|
||||
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 library, but without it you must define your own. These symbols
|
||||
are called "language items", and they each have an internal name, and then a
|
||||
signature that an implementation must conform to.
|
||||
|
||||
The first of these functions, `rust_eh_personality`, is used by the failure
|
||||
mechanisms of the compiler. This is often mapped to GCC's personality function
|
||||
(see the [libstd implementation][unwind] for more information), but crates
|
||||
which do not trigger a panic can be assured that this function is never
|
||||
called. The language item's name is `eh_personality`.
|
||||
|
||||
[unwind]: https://github.com/rust-lang/rust/blob/master/src/libpanic_unwind/gcc.rs
|
||||
|
||||
The second function, `rust_begin_panic`, is also used by the failure mechanisms of the
|
||||
compiler. When a panic happens, this controls the message that's displayed on
|
||||
the screen. While the language item's name is `panic_fmt`, the symbol name is
|
||||
`rust_begin_panic`.
|
||||
|
||||
A third function, `rust_eh_unwind_resume`, is also needed if the `custom_unwind_resume`
|
||||
flag is set in the options of the compilation target. It allows customizing the
|
||||
process of resuming unwind at the end of the landing pads. The language item's name
|
||||
is `eh_unwind_resume`.
|
||||
|
@ -4,5 +4,29 @@ The tracking issue for this feature is: [#29596]
|
||||
|
||||
[#29596]: https://github.com/rust-lang/rust/issues/29596
|
||||
|
||||
------------------------
|
||||
|
||||
You can tell `rustc` how to customize linking, and that is via the `link_args`
|
||||
attribute. This attribute is applied to `extern` blocks and specifies raw flags
|
||||
which need to get passed to the linker when producing an artifact. An example
|
||||
usage would be:
|
||||
|
||||
```rust,no_run
|
||||
#![feature(link_args)]
|
||||
|
||||
#[link_args = "-foo -bar -baz"]
|
||||
extern {}
|
||||
# fn main() {}
|
||||
```
|
||||
|
||||
Note that this feature is currently hidden behind the `feature(link_args)` gate
|
||||
because this is not a sanctioned way of performing linking. Right now `rustc`
|
||||
shells out to the system linker (`gcc` on most systems, `link.exe` on MSVC), so
|
||||
it makes sense to provide extra command line arguments, but this will not
|
||||
always be the case. In the future `rustc` may use LLVM directly to link native
|
||||
libraries, in which case `link_args` will have no meaning. You can achieve the
|
||||
same effect as the `link_args` attribute with the `-C link-args` argument to
|
||||
`rustc`.
|
||||
|
||||
It is highly recommended to *not* use this attribute, and rather use the more
|
||||
formal `#[link(...)]` attribute on `extern` blocks instead.
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#37406]
|
||||
|
||||
[#37406]: https://github.com/rust-lang/rust/issues/37406
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29602]
|
||||
|
||||
[#29602]: https://github.com/rust-lang/rust/issues/29602
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29603]
|
||||
|
||||
[#29603]: https://github.com/rust-lang/rust/issues/29603
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29598]
|
||||
|
||||
[#29598]: https://github.com/rust-lang/rust/issues/29598
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#37339]
|
||||
|
||||
[#37339]: https://github.com/rust-lang/rust/issues/37339
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29638]
|
||||
|
||||
[#29638]: https://github.com/rust-lang/rust/issues/29638
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29634]
|
||||
|
||||
[#29634]: https://github.com/rust-lang/rust/issues/29634
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#32408]
|
||||
|
||||
[#32408]: https://github.com/rust-lang/rust/issues/32408
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#27389]
|
||||
|
||||
[#27389]: https://github.com/rust-lang/rust/issues/27389
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#32837]
|
||||
|
||||
[#32837]: https://github.com/rust-lang/rust/issues/32837
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#35121]
|
||||
|
||||
[#35121]: https://github.com/rust-lang/rust/issues/35121
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29639]
|
||||
|
||||
[#29639]: https://github.com/rust-lang/rust/issues/29639
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29721]
|
||||
|
||||
[#29721]: https://github.com/rust-lang/rust/issues/29721
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#28979]
|
||||
|
||||
[#28979]: https://github.com/rust-lang/rust/issues/28979
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -2,3 +2,5 @@
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29628]
|
||||
|
||||
[#29628]: https://github.com/rust-lang/rust/issues/29628
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,6 @@ The tracking issue for this feature is: [#13231]
|
||||
|
||||
[#13231]: https://github.com/rust-lang/rust/issues/13231
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#32837]
|
||||
|
||||
[#32837]: https://github.com/rust-lang/rust/issues/32837
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#27779]
|
||||
|
||||
[#27779]: https://github.com/rust-lang/rust/issues/27779
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#27731]
|
||||
|
||||
[#27731]: https://github.com/rust-lang/rust/issues/27731
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,10 @@ The tracking issue for this feature is: [#29597]
|
||||
|
||||
[#29597]: https://github.com/rust-lang/rust/issues/29597
|
||||
|
||||
This feature is part of "compiler plugins." It will often be used with the
|
||||
[`plugin`] and `rustc_private` features as well. For more details, see
|
||||
their docs.
|
||||
|
||||
[`plugin`]: plugin.html
|
||||
|
||||
------------------------
|
||||
|
@ -5,4 +5,258 @@ The tracking issue for this feature is: [#29597]
|
||||
[#29597]: https://github.com/rust-lang/rust/issues/29597
|
||||
|
||||
|
||||
This feature is part of "compiler plugins." It will often be used with the
|
||||
[`plugin_registrar`] and `rustc_private` features.
|
||||
|
||||
[`plugin_registrar`]: plugin-registrar.html
|
||||
|
||||
------------------------
|
||||
|
||||
`rustc` can load compiler plugins, which are user-provided libraries that
|
||||
extend the compiler's behavior with new syntax extensions, lint checks, etc.
|
||||
|
||||
A plugin is a dynamic library crate with a designated *registrar* function that
|
||||
registers extensions with `rustc`. Other crates can load these extensions using
|
||||
the crate attribute `#![plugin(...)]`. See the
|
||||
`rustc_plugin` documentation for more about the
|
||||
mechanics of defining and loading a plugin.
|
||||
|
||||
If present, arguments passed as `#![plugin(foo(... args ...))]` are not
|
||||
interpreted by rustc itself. They are provided to the plugin through the
|
||||
`Registry`'s `args` method.
|
||||
|
||||
In the vast majority of cases, a plugin should *only* be used through
|
||||
`#![plugin]` and not through an `extern crate` item. Linking a plugin would
|
||||
pull in all of libsyntax and librustc as dependencies of your crate. This is
|
||||
generally unwanted unless you are building another plugin. The
|
||||
`plugin_as_library` lint checks these guidelines.
|
||||
|
||||
The usual practice is to put compiler plugins in their own crate, separate from
|
||||
any `macro_rules!` macros or ordinary Rust code meant to be used by consumers
|
||||
of a library.
|
||||
|
||||
# Syntax extensions
|
||||
|
||||
Plugins can extend Rust's syntax in various ways. One kind of syntax extension
|
||||
is the procedural macro. These are invoked the same way as [ordinary
|
||||
macros](macros.html), but the expansion is performed by arbitrary Rust
|
||||
code that manipulates syntax trees at
|
||||
compile time.
|
||||
|
||||
Let's write a plugin
|
||||
[`roman_numerals.rs`](https://github.com/rust-lang/rust/blob/master/src/test/run-pass-fulldeps/auxiliary/roman_numerals.rs)
|
||||
that implements Roman numeral integer literals.
|
||||
|
||||
```rust,ignore
|
||||
#![crate_type="dylib"]
|
||||
#![feature(plugin_registrar, rustc_private)]
|
||||
|
||||
extern crate syntax;
|
||||
extern crate rustc;
|
||||
extern crate rustc_plugin;
|
||||
|
||||
use syntax::parse::token;
|
||||
use syntax::tokenstream::TokenTree;
|
||||
use syntax::ext::base::{ExtCtxt, MacResult, DummyResult, MacEager};
|
||||
use syntax::ext::build::AstBuilder; // A trait for expr_usize.
|
||||
use syntax::ext::quote::rt::Span;
|
||||
use rustc_plugin::Registry;
|
||||
|
||||
fn expand_rn(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
|
||||
-> Box<MacResult + 'static> {
|
||||
|
||||
static NUMERALS: &'static [(&'static str, usize)] = &[
|
||||
("M", 1000), ("CM", 900), ("D", 500), ("CD", 400),
|
||||
("C", 100), ("XC", 90), ("L", 50), ("XL", 40),
|
||||
("X", 10), ("IX", 9), ("V", 5), ("IV", 4),
|
||||
("I", 1)];
|
||||
|
||||
if args.len() != 1 {
|
||||
cx.span_err(
|
||||
sp,
|
||||
&format!("argument should be a single identifier, but got {} arguments", args.len()));
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
|
||||
let text = match args[0] {
|
||||
TokenTree::Token(_, token::Ident(s)) => s.to_string(),
|
||||
_ => {
|
||||
cx.span_err(sp, "argument should be a single identifier");
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
};
|
||||
|
||||
let mut text = &*text;
|
||||
let mut total = 0;
|
||||
while !text.is_empty() {
|
||||
match NUMERALS.iter().find(|&&(rn, _)| text.starts_with(rn)) {
|
||||
Some(&(rn, val)) => {
|
||||
total += val;
|
||||
text = &text[rn.len()..];
|
||||
}
|
||||
None => {
|
||||
cx.span_err(sp, "invalid Roman numeral");
|
||||
return DummyResult::any(sp);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
MacEager::expr(cx.expr_usize(sp, total))
|
||||
}
|
||||
|
||||
#[plugin_registrar]
|
||||
pub fn plugin_registrar(reg: &mut Registry) {
|
||||
reg.register_macro("rn", expand_rn);
|
||||
}
|
||||
```
|
||||
|
||||
Then we can use `rn!()` like any other macro:
|
||||
|
||||
```rust,ignore
|
||||
#![feature(plugin)]
|
||||
#![plugin(roman_numerals)]
|
||||
|
||||
fn main() {
|
||||
assert_eq!(rn!(MMXV), 2015);
|
||||
}
|
||||
```
|
||||
|
||||
The advantages over a simple `fn(&str) -> u32` are:
|
||||
|
||||
* The (arbitrarily complex) conversion is done at compile time.
|
||||
* Input validation is also performed at compile time.
|
||||
* It can be extended to allow use in patterns, which effectively gives
|
||||
a way to define new literal syntax for any data type.
|
||||
|
||||
In addition to procedural macros, you can define new
|
||||
[`derive`](../reference.html#derive)-like attributes and other kinds of
|
||||
extensions. See `Registry::register_syntax_extension` and the `SyntaxExtension`
|
||||
enum. For a more involved macro example, see
|
||||
[`regex_macros`](https://github.com/rust-lang/regex/blob/master/regex_macros/src/lib.rs).
|
||||
|
||||
|
||||
## Tips and tricks
|
||||
|
||||
Some of the [macro debugging tips](macros.html#Debugging%20macro%20code) are applicable.
|
||||
|
||||
You can use `syntax::parse` to turn token trees into
|
||||
higher-level syntax elements like expressions:
|
||||
|
||||
```rust,ignore
|
||||
fn expand_foo(cx: &mut ExtCtxt, sp: Span, args: &[TokenTree])
|
||||
-> Box<MacResult+'static> {
|
||||
|
||||
let mut parser = cx.new_parser_from_tts(args);
|
||||
|
||||
let expr: P<Expr> = parser.parse_expr();
|
||||
```
|
||||
|
||||
Looking through [`libsyntax` parser
|
||||
code](https://github.com/rust-lang/rust/blob/master/src/libsyntax/parse/parser.rs)
|
||||
will give you a feel for how the parsing infrastructure works.
|
||||
|
||||
Keep the `Span`s of everything you parse, for better error reporting. You can
|
||||
wrap `Spanned` around your custom data structures.
|
||||
|
||||
Calling `ExtCtxt::span_fatal` will immediately abort compilation. It's better to
|
||||
instead call `ExtCtxt::span_err` and return `DummyResult` so that the compiler
|
||||
can continue and find further errors.
|
||||
|
||||
To print syntax fragments for debugging, you can use `span_note` together with
|
||||
`syntax::print::pprust::*_to_string`.
|
||||
|
||||
The example above produced an integer literal using `AstBuilder::expr_usize`.
|
||||
As an alternative to the `AstBuilder` trait, `libsyntax` provides a set of
|
||||
quasiquote macros. They are undocumented and very rough around the edges.
|
||||
However, the implementation may be a good starting point for an improved
|
||||
quasiquote as an ordinary plugin library.
|
||||
|
||||
|
||||
# Lint plugins
|
||||
|
||||
Plugins can extend [Rust's lint
|
||||
infrastructure](../reference.html#lint-check-attributes) with additional checks for
|
||||
code style, safety, etc. Now let's write a plugin
|
||||
[`lint_plugin_test.rs`](https://github.com/rust-lang/rust/blob/master/src/test/run-pass-fulldeps/auxiliary/lint_plugin_test.rs)
|
||||
that warns about any item named `lintme`.
|
||||
|
||||
```rust,ignore
|
||||
#![feature(plugin_registrar)]
|
||||
#![feature(box_syntax, rustc_private)]
|
||||
|
||||
extern crate syntax;
|
||||
|
||||
// Load rustc as a plugin to get macros
|
||||
#[macro_use]
|
||||
extern crate rustc;
|
||||
extern crate rustc_plugin;
|
||||
|
||||
use rustc::lint::{EarlyContext, LintContext, LintPass, EarlyLintPass,
|
||||
EarlyLintPassObject, LintArray};
|
||||
use rustc_plugin::Registry;
|
||||
use syntax::ast;
|
||||
|
||||
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");
|
||||
|
||||
struct Pass;
|
||||
|
||||
impl LintPass for Pass {
|
||||
fn get_lints(&self) -> LintArray {
|
||||
lint_array!(TEST_LINT)
|
||||
}
|
||||
}
|
||||
|
||||
impl EarlyLintPass for Pass {
|
||||
fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
|
||||
if it.ident.name.as_str() == "lintme" {
|
||||
cx.span_lint(TEST_LINT, it.span, "item is named 'lintme'");
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
#[plugin_registrar]
|
||||
pub fn plugin_registrar(reg: &mut Registry) {
|
||||
reg.register_early_lint_pass(box Pass as EarlyLintPassObject);
|
||||
}
|
||||
```
|
||||
|
||||
Then code like
|
||||
|
||||
```rust,ignore
|
||||
#![plugin(lint_plugin_test)]
|
||||
|
||||
fn lintme() { }
|
||||
```
|
||||
|
||||
will produce a compiler warning:
|
||||
|
||||
```txt
|
||||
foo.rs:4:1: 4:16 warning: item is named 'lintme', #[warn(test_lint)] on by default
|
||||
foo.rs:4 fn lintme() { }
|
||||
^~~~~~~~~~~~~~~
|
||||
```
|
||||
|
||||
The components of a lint plugin are:
|
||||
|
||||
* one or more `declare_lint!` invocations, which define static `Lint` structs;
|
||||
|
||||
* a struct holding any state needed by the lint pass (here, none);
|
||||
|
||||
* a `LintPass`
|
||||
implementation defining how to check each syntax element. A single
|
||||
`LintPass` may call `span_lint` for several different `Lint`s, but should
|
||||
register them all through the `get_lints` method.
|
||||
|
||||
Lint passes are syntax traversals, but they run at a late stage of compilation
|
||||
where type information is available. `rustc`'s [built-in
|
||||
lints](https://github.com/rust-lang/rust/blob/master/src/librustc/lint/builtin.rs)
|
||||
mostly use the same infrastructure as lint plugins, and provide examples of how
|
||||
to access type information.
|
||||
|
||||
Lints defined by plugins are controlled by the usual [attributes and compiler
|
||||
flags](../reference.html#lint-check-attributes), e.g. `#[allow(test_lint)]` or
|
||||
`-A test-lint`. These identifiers are derived from the first argument to
|
||||
`declare_lint!`, with appropriate case and punctuation conversion.
|
||||
|
||||
You can run `rustc -W help foo.rs` to see a list of lints known to `rustc`,
|
||||
including those provided by plugins loaded by `foo.rs`.
|
||||
|
@ -2,3 +2,5 @@
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#38356]
|
||||
|
||||
[#38356]: https://github.com/rust-lang/rust/issues/38356
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#32409]
|
||||
|
||||
[#32409]: https://github.com/rust-lang/rust/issues/32409
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29601]
|
||||
|
||||
[#29601]: https://github.com/rust-lang/rust/issues/29601
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#35626]
|
||||
|
||||
[#35626]: https://github.com/rust-lang/rust/issues/35626
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#27731]
|
||||
|
||||
[#27731]: https://github.com/rust-lang/rust/issues/27731
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29642]
|
||||
|
||||
[#29642]: https://github.com/rust-lang/rust/issues/29642
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -2,3 +2,5 @@
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
||||
|
@ -2,3 +2,5 @@
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#27731]
|
||||
|
||||
[#27731]: https://github.com/rust-lang/rust/issues/27731
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#27731]
|
||||
|
||||
[#27731]: https://github.com/rust-lang/rust/issues/27731
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,24 @@ The tracking issue for this feature is: [#23121]
|
||||
|
||||
[#23121]: https://github.com/rust-lang/rust/issues/23121
|
||||
|
||||
See also [`advanced_slice_patterns`](advanced-slice-patterns.html).
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
If you want to match against a slice or array, you can use `&` with the
|
||||
`slice_patterns` feature:
|
||||
|
||||
```rust
|
||||
#![feature(slice_patterns)]
|
||||
|
||||
fn main() {
|
||||
let v = vec!["match_this", "1"];
|
||||
|
||||
match &v[..] {
|
||||
&["match_this", second] => println!("The second element is {}", second),
|
||||
_ => {},
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
|
@ -2,7 +2,7 @@
|
||||
|
||||
The tracking issue for this feature is: [#31844]
|
||||
|
||||
[#31844]: https://github.com/rust-lang/rust/issues/31844
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -2,3 +2,5 @@
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29633]
|
||||
|
||||
[#29633]: https://github.com/rust-lang/rust/issues/29633
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#37403]
|
||||
|
||||
[#37403]: https://github.com/rust-lang/rust/issues/37403
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29719]
|
||||
|
||||
[#29719]: https://github.com/rust-lang/rust/issues/29719
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#15701]
|
||||
|
||||
[#15701]: https://github.com/rust-lang/rust/issues/15701
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#38814]
|
||||
|
||||
[#38814]: https://github.com/rust-lang/rust/issues/38814
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#31434]
|
||||
|
||||
[#31434]: https://github.com/rust-lang/rust/issues/31434
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -2,3 +2,5 @@
|
||||
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
||||
|
@ -1,7 +1,13 @@
|
||||
# Benchmark tests
|
||||
# `test`
|
||||
|
||||
Rust supports benchmark tests, which can test the performance of your
|
||||
code. Let's make our `src/lib.rs` look like this (comments elided):
|
||||
The tracking issue for this feature is: None.
|
||||
|
||||
------------------------
|
||||
|
||||
The internals of the `test` crate are unstable, behind the `test` flag. The
|
||||
most widely used part of the `test` crate are benchmark tests, which can test
|
||||
the performance of your code. Let's make our `src/lib.rs` look like this
|
||||
(comments elided):
|
||||
|
||||
```rust,ignore
|
||||
#![feature(test)]
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29594]
|
||||
|
||||
[#29594]: https://github.com/rust-lang/rust/issues/29594
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29598]
|
||||
|
||||
[#29598]: https://github.com/rust-lang/rust/issues/29598
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#23416]
|
||||
|
||||
[#23416]: https://github.com/rust-lang/rust/issues/23416
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
@ -4,5 +4,7 @@ The tracking issue for this feature is: [#29625]
|
||||
|
||||
[#29625]: https://github.com/rust-lang/rust/issues/29625
|
||||
|
||||
------------------------
|
||||
|
||||
|
||||
|
||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user