The Unstable Book

Welcome to the Unstable Book! This book consists of a number of chapters, each one organized by a "feature flag." That is, when using an unstable feature of Rust, you must use a flag, like this:

#![feature(box_syntax)]

fn main() {
    let five = box 5;
}

The box_syntax feature has a chapter describing how to use it.

Because this documentation relates to unstable features, we make no guarantees that what is contained here is accurate or up to date. It's developed on a best-effort basis. Each page will have a link to its tracking issue with the latest developments; you might want to check those as well.

Compiler flags

branch-protection

This option lets you enable branch authentication instructions on AArch64. This option is ignored for non-AArch64 architectures. It takes some combination of the following values, separated by a ,.

  • pac-ret - Enable pointer authentication for non-leaf functions.
  • leaf - Enable pointer authentication for all functions, including leaf functions.
  • b-key - Sign return addresses with key B, instead of the default key A.
  • bti - Enable branch target identification.

leaf and b-key are only valid if pac-ret was previously specified. For example, -Z branch-protection=bti,pac-ret,leaf is valid, but -Z branch-protection=bti,leaf,pac-ret is not.

Rust's standard library does not ship with BTI or pointer authentication enabled by default. In Cargo projects the standard library can be recompiled with pointer authentication using the nightly build-std feature.

cf-protection

This option enables control-flow enforcement technology (CET) on x86; a more detailed description of CET is available here. Similar to clang, this flag takes one of the following values:

  • none - Disable CET completely (this is the default).
  • branch - Enable indirect branch tracking (IBT).
  • return - Enable shadow stack (SHSTK).
  • full - Enable both branch and return.

This flag only applies to the LLVM backend: it sets the cf-protection-branch and cf-protection-return flags on LLVM modules. Note, however, that all compiled modules linked together must have the flags set for the compiled output to be CET-enabled. Currently, Rust's standard library does not ship with CET enabled by default, so you may need to rebuild all standard modules with a cargo command like:

$ RUSTFLAGS="-Z cf-protection=full" cargo +nightly build -Z build-std --target x86_64-unknown-linux-gnu

Detection

An ELF binary is CET-enabled if it has the IBT and SHSTK tags, e.g.:

$ readelf -a target/x86_64-unknown-linux-gnu/debug/example | grep feature:
      Properties: x86 feature: IBT, SHSTK

Troubleshooting

To display modules that are not CET enabled, examine the linker errors available when cet-report is enabled:

$ RUSTC_LOG=rustc_codegen_ssa::back::link=info rustc-custom -v -Z cf-protection=full -C link-arg="-Wl,-z,cet-report=warning" -o example example.rs
...
/usr/bin/ld: /.../build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/x86_64-unknown-linux-gnu/lib/libstd-d73f7266be14cb8b.rlib(std-d73f7266be14cb8b.std.f7443020-cgu.12.rcgu.o): warning: missing IBT and SHSTK properties

check-cfg

The tracking issue for this feature is: #82450.


This feature allows you to enable complete or partial checking of configuration.

rustc accepts the --check-cfg option, which specifies whether to check conditions and how to check them. The --check-cfg option takes a value, called the check cfg specification. The check cfg specification is parsed using the Rust metadata syntax, just as the --cfg option is.

--check-cfg option can take one of two forms:

  1. --check-cfg names(...) enables checking condition names.
  2. --check-cfg values(...) enables checking the values within list-valued conditions.

These two options are independent. names checks only the namespace of condition names while values checks only the namespace of the values of list-valued conditions.

NOTE: No implicit expectation is added when using --cfg for both forms. Users are expected to pass all expected names and values using names(...) and values(...).

The names(...) form

The names(...) form enables checking the names. This form uses a named list:

rustc --check-cfg 'names(name1, name2, ... nameN)'

where each name is a bare identifier (has no quotes). The order of the names is not significant.

If --check-cfg names(...) is specified at least once, then rustc will check all references to condition names. rustc will check every #[cfg] attribute, #[cfg_attr] attribute, cfg clause inside #[link] attribute and cfg!(...) call against the provided list of expected condition names. If a name is not present in this list, then rustc will report an unexpected_cfgs lint diagnostic. The default diagnostic level for this lint is Warn.

If --check-cfg names(...) is not specified, then rustc will not check references to condition names.

--check-cfg names(...) may be specified more than once. The result is that the list of valid condition names is merged across all options. It is legal for a condition name to be specified more than once; redundantly specifying a condition name has no effect.

To enable checking condition names with an empty set of valid condition names, use the following form. The parentheses are required.

rustc --check-cfg 'names()'

Note that --check-cfg 'names()' is not equivalent to omitting the option entirely. The first form enables checking condition names, while specifying that there are no valid condition names (outside of the set of well-known names defined by rustc). Omitting the --check-cfg 'names(...)' option does not enable checking condition names.

The values(...) form

The values(...) form enables checking the values within list-valued conditions. It has this form:

rustc --check-cfg `values(name, "value1", "value2", ... "valueN")'

where name is a bare identifier (has no quotes) and each "value" term is a quoted literal string. name specifies the name of the condition, such as feature or target_os.

When the values(...) option is specified, rustc will check every #[cfg(name = "value")] attribute, #[cfg_attr(name = "value")] attribute, #[link(name = "a", cfg(name = "value"))] and cfg!(name = "value") call. It will check that the "value" specified is present in the list of expected values. If "value" is not in it, then rustc will report an unexpected_cfgs lint diagnostic. The default diagnostic level for this lint is Warn.

To enable checking of values, but to provide an empty set of valid values, use this form:

rustc --check-cfg `values(name)`

The --check-cfg values(...) option can be repeated, both for the same condition name and for different names. If it is repeated for the same condition name, then the sets of values for that condition are merged together.

If values() is specified, then rustc will enable the checking of well-known values defined by itself. Note that it's necessary to specify the values() form to enable the checking of well known values, specifying the other forms doesn't implicitly enable it.

Examples

Consider this command line:

rustc --check-cfg 'names(feature)' \
      --check-cfg 'values(feature, "lion", "zebra")' \
      --cfg 'feature="lion"' -Z unstable-options \
      example.rs

This command line indicates that this crate has two features: lion and zebra. The lion feature is enabled, while the zebra feature is disabled. Consider compiling this code:

#![allow(unused)]
fn main() {
// This is expected, and tame_lion() will be compiled
#[cfg(feature = "lion")]
fn tame_lion(lion: Lion) {}

// This is expected, and ride_zebra() will NOT be compiled.
#[cfg(feature = "zebra")]
fn ride_zebra(zebra: Zebra) {}

// This is UNEXPECTED, and will cause a compiler warning (by default).
#[cfg(feature = "platypus")]
fn poke_platypus() {}

// This is UNEXPECTED, because 'feechure' is not a known condition name,
// and will cause a compiler warning (by default).
#[cfg(feechure = "lion")]
fn tame_lion() {}
}

Note: The --check-cfg names(feature) option is necessary only to enable checking the condition name, as in the last example. feature is a well-known (always-expected) condition name, and so it is not necessary to specify it in a --check-cfg 'names(...)' option. That option can be shortened to > --check-cfg names() in order to enable checking well-known condition names.

Example: Checking condition names, but not values

# This turns on checking for condition names, but not values, such as 'feature' values.
rustc --check-cfg 'names(is_embedded, has_feathers)' \
      --cfg has_feathers -Z unstable-options
#![allow(unused)]
fn main() {
#[cfg(is_embedded)]         // This is expected as "is_embedded" was provided in names()
fn do_embedded() {}

#[cfg(has_feathers)]        // This is expected as "has_feathers" was provided in names()
fn do_features() {}

#[cfg(has_feathers = "zapping")] // This is expected as "has_feathers" was provided in names()
                                 // and because no value checking was enable for "has_feathers"
                                 // no warning is emitted for the value "zapping"
fn do_zapping() {}

#[cfg(has_mumble_frotz)]    // This is UNEXPECTED because names checking is enable and
                            // "has_mumble_frotz" was not provided in names()
fn do_mumble_frotz() {}
}

Example: Checking feature values, but not condition names

# This turns on checking for feature values, but not for condition names.
rustc --check-cfg 'values(feature, "zapping", "lasers")' \
      --cfg 'feature="zapping"' -Z unstable-options
#![allow(unused)]
fn main() {
#[cfg(is_embedded)]         // This is doesn't raise a warning, because names checking was not
                            // enable (ie not names())
fn do_embedded() {}

#[cfg(has_feathers)]        // Same as above, --check-cfg names(...) was never used so no name
                            // checking is performed
fn do_features() {}


#[cfg(feature = "lasers")]  // This is expected, "lasers" is in the values(feature) list
fn shoot_lasers() {}

#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in the
                            // --check-cfg values(feature) list
fn write_shakespeare() {}
}

Example: Checking both condition names and feature values

# This turns on checking for feature values and for condition names.
rustc --check-cfg 'names(is_embedded, has_feathers)' \
      --check-cfg 'values(feature, "zapping", "lasers")' \
      --cfg has_feathers --cfg 'feature="zapping"' -Z unstable-options
#![allow(unused)]
fn main() {
#[cfg(is_embedded)]         // This is expected because "is_embedded" was provided in names()
fn do_embedded() {}

#[cfg(has_feathers)]        // This is expected because "has_feathers" was provided in names()
fn do_features() {}

#[cfg(has_mumble_frotz)]    // This is UNEXPECTED, because has_mumble_frotz is not in the
                            // --check-cfg names(...) list
fn do_mumble_frotz() {}

#[cfg(feature = "lasers")]  // This is expected, "lasers" is in the values(feature) list
fn shoot_lasers() {}

#[cfg(feature = "monkeys")] // This is UNEXPECTED, because "monkeys" is not in
                            // the values(feature) list
fn write_shakespear() {}
}

codegen-backend

The tracking issue for this feature is: #77933.


This feature allows you to specify a path to a dynamic library to use as rustc's code generation backend at runtime.

Set the -Zcodegen-backend=<path> compiler flag to specify the location of the backend. The library must be of crate type dylib and must contain a function named __rustc_codegen_backend with a signature of fn() -> Box<dyn rustc_codegen_ssa::traits::CodegenBackend>.

Example

See also the hotplug_codegen_backend test for a full example.

use rustc_codegen_ssa::traits::CodegenBackend;

struct MyBackend;

impl CodegenBackend for MyBackend {
   // Implement codegen methods
}

#[no_mangle]
pub fn __rustc_codegen_backend() -> Box<dyn CodegenBackend> {
    Box::new(MyBackend)
}

control-flow-guard

The tracking issue for this feature is: #68793.


The rustc flag -Z control-flow-guard enables the Windows Control Flow Guard (CFG) platform security feature.

CFG is an exploit mitigation designed to enforce control-flow integrity for software running on supported Windows platforms (Windows 8.1 onwards). Specifically, CFG uses runtime checks to validate the target address of every indirect call/jump before allowing the call to complete.

During compilation, the compiler identifies all indirect calls/jumps and adds CFG checks. It also emits metadata containing the relative addresses of all address-taken functions. At runtime, if the binary is run on a CFG-aware operating system, the loader uses the CFG metadata to generate a bitmap of the address space and marks those addresses that contain valid targets. On each indirect call, the inserted check determines whether the target address is marked in this bitmap. If the target is not valid, the process is terminated.

In terms of interoperability:

  • Code compiled with CFG enabled can be linked with libraries and object files that are not compiled with CFG. In this case, a CFG-aware linker can identify address-taken functions in the non-CFG libraries.
  • Libraries compiled with CFG can linked into non-CFG programs. In this case, the CFG runtime checks in the libraries are not used (i.e. the mitigation is completely disabled).

CFG functionality is completely implemented in the LLVM backend and is supported for X86 (32-bit and 64-bit), ARM, and Aarch64 targets. The rustc flag adds the relevant LLVM module flags to enable the feature. This flag will be ignored for all non-Windows targets.

When to use Control Flow Guard

The primary motivation for enabling CFG in Rust is to enhance security when linking against non-Rust code, especially C/C++ code. To achieve full CFG protection, all indirect calls (including any from Rust code) must have the appropriate CFG checks, as added by this flag. CFG can also improve security for Rust code that uses the unsafe keyword.

Another motivation behind CFG is to harden programs against return-oriented programming (ROP) attacks. CFG disallows an attacker from taking advantage of the program's own instructions while redirecting control flow in unexpected ways.

Overhead of Control Flow Guard

The CFG checks and metadata can potentially increase binary size and runtime overhead. The magnitude of any increase depends on the number and frequency of indirect calls. For example, enabling CFG for the Rust standard library increases binary size by approximately 0.14%. Enabling CFG in the SPEC CPU 2017 Integer Speed benchmark suite (compiled with Clang/LLVM) incurs approximate runtime overheads of between 0% and 8%, with a geometric mean of 2.9%.

Testing Control Flow Guard

The rustc flag -Z control-flow-guard=nochecks instructs LLVM to emit the list of valid call targets without inserting runtime checks. This flag should only be used for testing purposes as it does not provide security enforcement.

Control Flow Guard in libraries

It is strongly recommended to also enable CFG checks for all linked libraries, including the standard library.

To enable CFG in the standard library, use the cargo -Z build-std functionality to recompile the standard library with the same configuration options as the main program.

For example:

rustup toolchain install --force nightly
rustup component add rust-src
SET RUSTFLAGS=-Z control-flow-guard
cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc
rustup toolchain install --force nightly
rustup component add rust-src
$Env:RUSTFLAGS = "-Z control-flow-guard"
cargo +nightly build -Z build-std --target x86_64-pc-windows-msvc

Alternatively, if you are building the standard library from source, you can set control-flow-guard = true in the config.toml file.

debug-info-for-profiling


Introduction

Automatic Feedback Directed Optimization (AFDO) is a method for using sampling based profiles to guide optimizations. This is contrasted with other methods of FDO or profile-guided optimization (PGO) which use instrumented profiling.

Unlike PGO (controlled by the rustc flags -Cprofile-generate and -Cprofile-use), a binary being profiled does not perform significantly worse, and thus it's possible to profile binaries used in real workflows and not necessary to construct artificial workflows.

Use

In order to use AFDO, the target platform must be Linux running on an x86_64 architecture with the performance profiler perf available. In addition, the external tool create_llvm_prof from this repository must be used.

Given a Rust file main.rs, we can produce an optimized binary as follows:

rustc -O -Zdebug-info-for-profiling main.rs -o main
perf record -b ./main
create_llvm_prof --binary=main --out=code.prof
rustc -O -Zprofile-sample-use=code.prof main.rs -o main2

The perf command produces a profile perf.data, which is then used by the create_llvm_prof command to create code.prof. This final profile is then used by rustc to guide optimizations in producing the binary main2.

dwarf-version

This option controls the version of DWARF that the compiler emits, on platforms that use DWARF to encode debug information. It takes one of the following values:

  • 2: DWARF version 2 (the default on certain platforms, like macOS).
  • 4: DWARF version 4 (the default on certain platforms, like Linux).
  • 5: DWARF version 5.

emit-stack-sizes

The tracking issue for this feature is: #54192


The rustc flag -Z emit-stack-sizes makes LLVM emit stack size metadata.

NOTE: This LLVM feature only supports the ELF object format as of LLVM 8.0. Using this flag with targets that use other object formats (e.g. macOS and Windows) will result in it being ignored.

Consider this crate:

#![crate_type = "lib"]

use std::ptr;

pub fn foo() {
    // this function doesn't use the stack
}

pub fn bar() {
    let xs = [0u32; 2];

    // force LLVM to allocate `xs` on the stack
    unsafe { ptr::read_volatile(&xs.as_ptr()); }
}

Using the -Z emit-stack-sizes flag produces extra linker sections in the output object file.

$ rustc -C opt-level=3 --emit=obj foo.rs

$ size -A foo.o
foo.o  :
section                                 size   addr
.text                                      0      0
.text._ZN3foo3foo17he211d7b4a3a0c16eE      1      0
.text._ZN3foo3bar17h1acb594305f70c2eE     22      0
.note.GNU-stack                            0      0
.eh_frame                                 72      0
Total                                     95

$ rustc -C opt-level=3 --emit=obj -Z emit-stack-sizes foo.rs

$ size -A foo.o
foo.o  :
section                                 size   addr
.text                                      0      0
.text._ZN3foo3foo17he211d7b4a3a0c16eE      1      0
.stack_sizes                               9      0
.text._ZN3foo3bar17h1acb594305f70c2eE     22      0
.stack_sizes                               9      0
.note.GNU-stack                            0      0
.eh_frame                                 72      0
Total                                    113

As of LLVM 7.0 the data will be written into a section named .stack_sizes and the format is "an array of pairs of function symbol values (pointer size) and stack sizes (unsigned LEB128)".

$ objdump -d foo.o

foo.o:     file format elf64-x86-64

Disassembly of section .text._ZN3foo3foo17he211d7b4a3a0c16eE:

0000000000000000 <_ZN3foo3foo17he211d7b4a3a0c16eE>:
   0:   c3                      retq

Disassembly of section .text._ZN3foo3bar17h1acb594305f70c2eE:

0000000000000000 <_ZN3foo3bar17h1acb594305f70c2eE>:
   0:   48 83 ec 10             sub    $0x10,%rsp
   4:   48 8d 44 24 08          lea    0x8(%rsp),%rax
   9:   48 89 04 24             mov    %rax,(%rsp)
   d:   48 8b 04 24             mov    (%rsp),%rax
  11:   48 83 c4 10             add    $0x10,%rsp
  15:   c3                      retq

$ objdump -s -j .stack_sizes foo.o

foo.o:     file format elf64-x86-64

Contents of section .stack_sizes:
 0000 00000000 00000000 00                 .........
Contents of section .stack_sizes:
 0000 00000000 00000000 10                 .........

It's important to note that linkers will discard this linker section by default. To preserve the section you can use a linker script like the one shown below.

/* file: keep-stack-sizes.x */
SECTIONS
{
  /* `INFO` makes the section not allocatable so it won't be loaded into memory */
  .stack_sizes (INFO) :
  {
    KEEP(*(.stack_sizes));
  }
}

The linker script must be passed to the linker using a rustc flag like -C link-arg.

// file: src/main.rs
use std::ptr;

#[inline(never)]
fn main() {
    let xs = [0u32; 2];

    // force LLVM to allocate `xs` on the stack
    unsafe { ptr::read_volatile(&xs.as_ptr()); }
}
$ RUSTFLAGS="-Z emit-stack-sizes" cargo build --release

$ size -A target/release/hello | grep stack_sizes || echo section was not found
section was not found

$ RUSTFLAGS="-Z emit-stack-sizes" cargo rustc --release -- \
    -C link-arg=-Wl,-Tkeep-stack-sizes.x \
    -C link-arg=-N

$ size -A target/release/hello | grep stack_sizes
.stack_sizes                               90   176272

$ # non-allocatable section (flags don't contain the "A" (alloc) flag)
$ readelf -S target/release/hello
Section Headers:
  [Nr]   Name              Type             Address           Offset
       Size              EntSize            Flags  Link  Info  Align
(..)
  [1031] .stack_sizes      PROGBITS         000000000002b090  0002b0f0
       000000000000005a  0000000000000000   L       5     0     1

$ objdump -s -j .stack_sizes target/release/hello

target/release/hello:     file format elf64-x86-64

Contents of section .stack_sizes:
 2b090 c0040000 00000000 08f00400 00000000  ................
 2b0a0 00080005 00000000 00000810 05000000  ................
 2b0b0 00000000 20050000 00000000 10400500  .... ........@..
 2b0c0 00000000 00087005 00000000 00000080  ......p.........
 2b0d0 05000000 00000000 90050000 00000000  ................
 2b0e0 00a00500 00000000 0000               ..........

Author note: I'm not entirely sure why, in this case, -N is required in addition to -Tkeep-stack-sizes.x. For example, it's not required when producing statically linked files for the ARM Cortex-M architecture.

--extern Options

  • Tracking issue for --extern crate modifiers: #98405
  • Tracking issue for noprelude: #98398
  • Tracking issue for priv: #98399
  • Tracking issue for nounused: #98400

The behavior of the --extern flag can be modified with noprelude, priv or nounused options.

This is unstable feature, so you have to provide -Zunstable-options to enable it.

Examples

Use your own build of the core crate.

rustc main.rs -Z unstable-options --extern noprelude:core=libcore.rlib

To use multiple options, separate them with a comma:

rustc main.rs -Z unstable-options --extern noprelude,priv,nounused:mydep=mydep.rlib

Options

  • noprelude: Do not add the crate to the external prelude. If used, it will need to be imported using extern crate. This is used by the build-std project to simulate compatibility with sysroot-only crates.
  • priv: Mark the crate as a private dependency for the exported_private_dependencies lint.
  • nounused: Suppress unused-crate-dependencies warnings for the crate.

location-detail

The tracking issue for this feature is: #70580.


Option -Z location-detail=val controls what location details are tracked when using caller_location. This allows users to control what location details are printed as part of panic messages, by allowing them to exclude any combination of filenames, line numbers, and column numbers. This option is intended to provide users with a way to mitigate the size impact of #[track_caller].

This option supports a comma separated list of location details to be included. Valid options within this list are:

  • file - the filename of the panic will be included in the panic output
  • line - the source line of the panic will be included in the panic output
  • column - the source column of the panic will be included in the panic output

Any combination of these three options are supported. Alternatively, you can pass none to this option, which results in no location details being tracked. If this option is not specified, all three are included by default.

An example of a panic output when using -Z location-detail=line:

panicked at 'Process blink had a fault', <redacted>:323:0

The code size savings from this option are two-fold. First, the &'static str values for each path to a file containing a panic are removed from the binary. For projects with deep directory structures and many files with panics, this can add up. This category of savings can only be realized by excluding filenames from the panic output. Second, savings can be realized by allowing multiple panics to be fused into a single panicking branch. It is often the case that within a single file, multiple panics with the same panic message exist -- e.g. two calls to Option::unwrap() in a single line, or two calls to Result::expect() on adjacent lines. If column and line information are included in the Location struct passed to the panic handler, these branches cannot be fused, as the output is different depending on which panic occurs. However if line and column information is identical for all panics, these branches can be fused, which can lead to substantial code size savings, especially for small embedded binaries with many panics.

The savings from this option are amplified when combined with the use of -Zbuild-std, as otherwise paths for panics within the standard library are still included in your binary.

move_size_limit


The -Zmove-size-limit=N compiler flag enables large_assignments lints which will warn when moving objects whose size exceeds N bytes.

Lint warns only about moves in functions that participate in code generation. Consequently it will be ineffective for compiler invocatation that emit metadata only, i.e., cargo check like workflows.

no-unique-section-names


This flag currently applies only to ELF-based targets using the LLVM codegen backend. It prevents the generation of unique ELF section names for each separate code and data item when -Z function-sections is also in use, which is the default for most targets. This option can reduce the size of object files, and depending on the linker, the final ELF binary as well.

For example, a function func will by default generate a code section called .text.func. Normally this is fine because the linker will merge all those .text.* sections into a single one in the binary. However, starting with LLVM 12, the backend will also generate unique section names for exception handling, so you would see a section name of .gcc_except_table.func in the object file and potentially in the final ELF binary, which could add significant bloat to programs that contain many functions.

This flag instructs LLVM to use the same .text and .gcc_except_table section name for each function, and it is analogous to Clang's -fno-unique-section-names option.

profile

The tracking issue for this feature is: #42524.


This feature allows the generation of code coverage reports.

Set the -Zprofile compiler flag in order to enable gcov profiling.

For example:

cargo new testgcov --bin
cd testgcov
export RUSTFLAGS="-Zprofile -Ccodegen-units=1 -Copt-level=0 -Clink-dead-code -Coverflow-checks=off -Zpanic_abort_tests -Cpanic=abort"
export CARGO_INCREMENTAL=0
cargo build
cargo run

Once you've built and run your program, files with the gcno (after build) and gcda (after execution) extensions will be created. You can parse them with llvm-cov gcov or grcov.

Please note that RUSTFLAGS by default applies to everything that cargo builds and runs during a build! When the --target flag is explicitly passed to cargo, the RUSTFLAGS no longer apply to build scripts and procedural macros. For more fine-grained control consider passing a RUSTC_WRAPPER program to cargo that only adds the profiling flags to rustc for the specific crates you want to profile.

`profile-sample-use


-Zprofile-sample-use=code.prof directs rustc to use the profile code.prof as a source for Automatic Feedback Directed Optimization (AFDO). See the documentation of -Zdebug-info-for-profiling for more information on using AFDO.

remap-cwd-prefix

The tracking issue for this feature is: #87325.


This flag will rewrite absolute paths under the current working directory, replacing the current working directory prefix with a specified value.

The given value may be absolute or relative, or empty. This switch takes precedence over --remap-path-prefix in case they would both match a given path.

This flag helps to produce deterministic output, by removing the current working directory from build output, while allowing the command line to be universally reproducible, such that the same execution will work on all machines, regardless of build environment.

Example

# This would produce an absolute path to main.rs in build outputs of
# "./main.rs".
rustc -Z remap-cwd-prefix=. main.rs

report-time

The tracking issue for this feature is: #64888


The report-time feature adds a possibility to report execution time of the tests generated via libtest.

This is unstable feature, so you have to provide -Zunstable-options to get this feature working.

Sample usage command:

./test_executable -Zunstable-options --report-time

Available options:

--report-time
                Show execution time of each test.
                Threshold values for colorized output can be
                configured via
                `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION`
                and
                `RUST_TEST_TIME_DOCTEST` environment variables.
                Expected format of environment variable is
                `VARIABLE=WARN_TIME,CRITICAL_TIME`.
                Not available for --format=terse
--ensure-time
                Treat excess of the test execution time limit as
                error.
                Threshold values for this option can be configured via
                `RUST_TEST_TIME_UNIT`, `RUST_TEST_TIME_INTEGRATION`
                and
                `RUST_TEST_TIME_DOCTEST` environment variables.
                Expected format of environment variable is
                `VARIABLE=WARN_TIME,CRITICAL_TIME`.
                `CRITICAL_TIME` here means the limit that should not be
                exceeded by test.

Example of the environment variable format:

RUST_TEST_TIME_UNIT=100,200

where 100 stands for warn time, and 200 stands for critical time.

Examples

cargo test --tests -- -Zunstable-options --report-time
    Finished dev [unoptimized + debuginfo] target(s) in 0.02s
     Running target/debug/deps/example-27fb188025bec02c

running 3 tests
test tests::unit_test_quick ... ok <0.000s>
test tests::unit_test_warn ... ok <0.055s>
test tests::unit_test_critical ... ok <0.110s>

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

     Running target/debug/deps/tests-cedb06f6526d15d9

running 3 tests
test unit_test_quick ... ok <0.000s>
test unit_test_warn ... ok <0.550s>
test unit_test_critical ... ok <1.100s>

test result: ok. 3 passed; 0 failed; 0 ignored; 0 measured; 0 filtered out

sanitizer

The tracking issues for this feature are:


This feature allows for use of one of following sanitizers:

To enable a sanitizer compile with -Zsanitizer=address,-Zsanitizer=cfi, -Zsanitizer=hwaddress, -Zsanitizer=leak, -Zsanitizer=memory, -Zsanitizer=memtag, -Zsanitizer=shadow-call-stack, or -Zsanitizer=thread. You might also need the --target and build-std flags. Example:

$ RUSTFLAGS=-Zsanitizer=address cargo build -Zbuild-std --target x86_64-unknown-linux-gnu

AddressSanitizer

AddressSanitizer is a memory error detector. It can detect the following types of bugs:

  • Out of bound accesses to heap, stack and globals
  • Use after free
  • Use after return (runtime flag ASAN_OPTIONS=detect_stack_use_after_return=1)
  • Use after scope
  • Double-free, invalid free
  • Memory leaks

The memory leak detection is enabled by default on Linux, and can be enabled with runtime flag ASAN_OPTIONS=detect_leaks=1 on macOS.

AddressSanitizer is supported on the following targets:

  • aarch64-apple-darwin
  • aarch64-fuchsia
  • aarch64-unknown-linux-gnu
  • x86_64-apple-darwin
  • x86_64-fuchsia
  • x86_64-unknown-freebsd
  • x86_64-unknown-linux-gnu

AddressSanitizer works with non-instrumented code although it will impede its ability to detect some bugs. It is not expected to produce false positive reports.

See the Clang AddressSanitizer documentation for more details.

Examples

Stack buffer overflow:

fn main() {
    let xs = [0, 1, 2, 3];
    let _y = unsafe { *xs.as_ptr().offset(4) };
}
$ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
==37882==ERROR: AddressSanitizer: stack-buffer-overflow on address 0x7ffe400e6250 at pc 0x5609a841fb20 bp 0x7ffe400e6210 sp 0x7ffe400e6208
READ of size 4 at 0x7ffe400e6250 thread T0
    #0 0x5609a841fb1f in example::main::h628ffc6626ed85b2 /.../src/main.rs:3:23
    ...

Address 0x7ffe400e6250 is located in stack of thread T0 at offset 48 in frame
    #0 0x5609a841f8af in example::main::h628ffc6626ed85b2 /.../src/main.rs:1

  This frame has 1 object(s):
    [32, 48) 'xs' (line 2) <== Memory access at offset 48 overflows this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-buffer-overflow /.../src/main.rs:3:23 in example::main::h628ffc6626ed85b2
Shadow bytes around the buggy address:
  0x100048014bf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100048014c00: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100048014c10: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100048014c20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100048014c30: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x100048014c40: 00 00 00 00 f1 f1 f1 f1 00 00[f3]f3 00 00 00 00
  0x100048014c50: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100048014c60: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x100048014c70: f1 f1 f1 f1 00 00 f3 f3 00 00 00 00 00 00 00 00
  0x100048014c80: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
  0x100048014c90: 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==37882==ABORTING

Use of a stack object after its scope has already ended:

static mut P: *mut usize = std::ptr::null_mut();

fn main() {
    unsafe {
        {
            let mut x = 0;
            P = &mut x;
        }
        std::ptr::write_volatile(P, 123);
    }
}
$ export RUSTFLAGS=-Zsanitizer=address RUSTDOCFLAGS=-Zsanitizer=address
$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
=================================================================
==39249==ERROR: AddressSanitizer: stack-use-after-scope on address 0x7ffc7ed3e1a0 at pc 0x55c98b262a8e bp 0x7ffc7ed3e050 sp 0x7ffc7ed3e048
WRITE of size 8 at 0x7ffc7ed3e1a0 thread T0
    #0 0x55c98b262a8d in core::ptr::write_volatile::he21f1df5a82f329a /.../src/rust/src/libcore/ptr/mod.rs:1048:5
    #1 0x55c98b262cd2 in example::main::h628ffc6626ed85b2 /.../src/main.rs:9:9
    ...

Address 0x7ffc7ed3e1a0 is located in stack of thread T0 at offset 32 in frame
    #0 0x55c98b262bdf in example::main::h628ffc6626ed85b2 /.../src/main.rs:3

  This frame has 1 object(s):
    [32, 40) 'x' (line 6) <== Memory access at offset 32 is inside this variable
HINT: this may be a false positive if your program uses some custom stack unwind mechanism, swapcontext or vfork
      (longjmp and C++ exceptions *are* supported)
SUMMARY: AddressSanitizer: stack-use-after-scope /.../src/rust/src/libcore/ptr/mod.rs:1048:5 in core::ptr::write_volatile::he21f1df5a82f329a
Shadow bytes around the buggy address:
  0x10000fd9fbe0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000fd9fbf0: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000fd9fc00: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
  0x10000fd9fc10: f8 f8 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000fd9fc20: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
=>0x10000fd9fc30: f1 f1 f1 f1[f8]f3 f3 f3 00 00 00 00 00 00 00 00
  0x10000fd9fc40: 00 00 00 00 00 00 00 00 00 00 00 00 f1 f1 f1 f1
  0x10000fd9fc50: 00 00 f3 f3 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000fd9fc60: 00 00 00 00 00 00 00 00 f1 f1 f1 f1 00 00 f3 f3
  0x10000fd9fc70: 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00 00
  0x10000fd9fc80: 00 00 00 00 f1 f1 f1 f1 00 00 f3 f3 00 00 00 00
Shadow byte legend (one shadow byte represents 8 application bytes):
  Addressable:           00
  Partially addressable: 01 02 03 04 05 06 07
  Heap left redzone:       fa
  Freed heap region:       fd
  Stack left redzone:      f1
  Stack mid redzone:       f2
  Stack right redzone:     f3
  Stack after return:      f5
  Stack use after scope:   f8
  Global redzone:          f9
  Global init order:       f6
  Poisoned by user:        f7
  Container overflow:      fc
  Array cookie:            ac
  Intra object redzone:    bb
  ASan internal:           fe
  Left alloca redzone:     ca
  Right alloca redzone:    cb
  Shadow gap:              cc
==39249==ABORTING

ControlFlowIntegrity

The LLVM Control Flow Integrity (CFI) support in the Rust compiler initially provides forward-edge control flow protection for Rust-compiled code only by aggregating function pointers in groups identified by their return and parameter types.

Forward-edge control flow protection for C or C++ and Rust -compiled code "mixed binaries" (i.e., for when C or C++ and Rust -compiled code share the same virtual address space) will be provided in later work by defining and using compatible type identifiers (see Type metadata in the design document in the tracking issue #89653).

LLVM CFI can be enabled with -Zsanitizer=cfi and requires LTO (i.e., -Clto).

See the Clang ControlFlowIntegrity documentation for more details.

Example

#![feature(naked_functions)]

use std::arch::asm;
use std::mem;

fn add_one(x: i32) -> i32 {
    x + 1
}

#[naked]
pub extern "C" fn add_two(x: i32) {
    // x + 2 preceded by a landing pad/nop block
    unsafe {
        asm!(
            "
             nop
             nop
             nop
             nop
             nop
             nop
             nop
             nop
             nop
             lea rax, [rdi+2]
             ret
        ",
            options(noreturn)
        );
    }
}

fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
    f(arg) + f(arg)
}

fn main() {
    let answer = do_twice(add_one, 5);

    println!("The answer is: {}", answer);

    println!("With CFI enabled, you should not see the next answer");
    let f: fn(i32) -> i32 = unsafe {
        // Offsets 0-8 make it land in the landing pad/nop block, and offsets 1-8 are
        // invalid branch/call destinations (i.e., within the body of the function).
        mem::transmute::<*const u8, fn(i32) -> i32>((add_two as *const u8).offset(5))
    };
    let next_answer = do_twice(f, 5);

    println!("The next answer is: {}", next_answer);
}

Fig. 1. Modified example from the Advanced Functions and Closures chapter of the The Rust Programming Language book.

$ cargo run --release
   Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
    Finished release [optimized] target(s) in 0.76s
     Running `target/release/rust-cfi-1`
The answer is: 12
With CFI enabled, you should not see the next answer
The next answer is: 14
$

Fig. 2. Build and execution of the modified example with LLVM CFI disabled.

$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
   Compiling rust-cfi-1 v0.1.0 (/home/rcvalle/rust-cfi-1)
    Finished release [optimized] target(s) in 3.39s
     Running `target/release/rust-cfi-1`
The answer is: 12
With CFI enabled, you should not see the next answer
Illegal instruction
$

Fig. 3. Build and execution of the modified example with LLVM CFI enabled.

When LLVM CFI is enabled, if there are any attempts to change/hijack control flow using an indirect branch/call to an invalid destination, the execution is terminated (see Fig. 3).

use std::mem;

fn add_one(x: i32) -> i32 {
    x + 1
}

fn add_two(x: i32, _y: i32) -> i32 {
    x + 2
}

fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
    f(arg) + f(arg)
}

fn main() {
    let answer = do_twice(add_one, 5);

    println!("The answer is: {}", answer);

    println!("With CFI enabled, you should not see the next answer");
    let f: fn(i32) -> i32 =
        unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
    let next_answer = do_twice(f, 5);

    println!("The next answer is: {}", next_answer);
}

Fig. 4. Another modified example from the Advanced Functions and Closures chapter of the The Rust Programming Language book.

$ cargo run --release
   Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
    Finished release [optimized] target(s) in 0.76s
     Running `target/release/rust-cfi-2`
The answer is: 12
With CFI enabled, you should not see the next answer
The next answer is: 14
$

Fig. 5. Build and execution of the modified example with LLVM CFI disabled.

$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
   Compiling rust-cfi-2 v0.1.0 (/home/rcvalle/rust-cfi-2)
    Finished release [optimized] target(s) in 3.38s
     Running `target/release/rust-cfi-2`
The answer is: 12
With CFI enabled, you should not see the next answer
Illegal instruction
$

Fig. 6. Build and execution of the modified example with LLVM CFI enabled.

When LLVM CFI is enabled, if there are any attempts to change/hijack control flow using an indirect branch/call to a function with different number of parameters than arguments intended/passed in the call/branch site, the execution is also terminated (see Fig. 6).

use std::mem;

fn add_one(x: i32) -> i32 {
    x + 1
}

fn add_two(x: i64) -> i64 {
    x + 2
}

fn do_twice(f: fn(i32) -> i32, arg: i32) -> i32 {
    f(arg) + f(arg)
}

fn main() {
    let answer = do_twice(add_one, 5);

    println!("The answer is: {}", answer);

    println!("With CFI enabled, you should not see the next answer");
    let f: fn(i32) -> i32 =
        unsafe { mem::transmute::<*const u8, fn(i32) -> i32>(add_two as *const u8) };
    let next_answer = do_twice(f, 5);

    println!("The next answer is: {}", next_answer);
}

Fig. 7. Another modified example from the Advanced Functions and Closures chapter of the The Rust Programming Language book.

 cargo run --release
   Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
    Finished release [optimized] target(s) in 0.74s
     Running `target/release/rust-cfi-3`
The answer is: 12
With CFI enabled, you should not see the next answer
The next answer is: 14
$

Fig. 8. Build and execution of the modified example with LLVM CFI disabled.

$ RUSTFLAGS="-Zsanitizer=cfi -Cembed-bitcode=yes -Clto" cargo run --release
   Compiling rust-cfi-3 v0.1.0 (/home/rcvalle/rust-cfi-3)
    Finished release [optimized] target(s) in 3.40s
     Running `target/release/rust-cfi-3`
The answer is: 12
With CFI enabled, you should not see the next answer
Illegal instruction
$

Fig. 9. Build and execution of the modified example with LLVM CFI enabled.

When LLVM CFI is enabled, if there are any attempts to change/hijack control flow using an indirect branch/call to a function with different return and parameter types than the return type expected and arguments intended/passed in the call/branch site, the execution is also terminated (see Fig. 9).

HWAddressSanitizer

HWAddressSanitizer is a newer variant of AddressSanitizer that consumes much less memory.

HWAddressSanitizer is supported on the following targets:

  • aarch64-linux-android
  • aarch64-unknown-linux-gnu

HWAddressSanitizer requires tagged-globals target feature to instrument globals. To enable this target feature compile with -C target-feature=+tagged-globals

See the Clang HWAddressSanitizer documentation for more details.

Example

Heap buffer overflow:

fn main() {
    let xs = vec![0, 1, 2, 3];
    let _y = unsafe { *xs.as_ptr().offset(4) };
}
$ rustc main.rs -Zsanitizer=hwaddress -C target-feature=+tagged-globals -C
linker=aarch64-linux-gnu-gcc -C link-arg=-fuse-ld=lld --target
aarch64-unknown-linux-gnu
$ ./main
==241==ERROR: HWAddressSanitizer: tag-mismatch on address 0xefdeffff0050 at pc 0xaaaae0ae4a98
READ of size 4 at 0xefdeffff0050 tags: 2c/00 (ptr/mem) in thread T0
    #0 0xaaaae0ae4a94  (/.../main+0x54a94)
    ...

[0xefdeffff0040,0xefdeffff0060) is a small allocated heap chunk; size: 32 offset: 16
0xefdeffff0050 is located 0 bytes to the right of 16-byte region [0xefdeffff0040,0xefdeffff0050)
allocated here:
    #0 0xaaaae0acb80c  (/.../main+0x3b80c)
    ...

Thread: T0 0xeffe00002000 stack: [0xffffc28ad000,0xffffc30ad000) sz: 8388608 tls: [0xffffaa10a020,0xffffaa10a7d0)
Memory tags around the buggy address (one tag corresponds to 16 bytes):
  0xfefcefffef80: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefcefffef90: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefcefffefa0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefcefffefb0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefcefffefc0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefcefffefd0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefcefffefe0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefcefffeff0: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
=>0xfefceffff000: d7  d7  05  00  2c [00] 00  00  00  00  00  00  00  00  00  00
  0xfefceffff010: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefceffff020: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefceffff030: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefceffff040: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefceffff050: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefceffff060: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefceffff070: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
  0xfefceffff080: 00  00  00  00  00  00  00  00  00  00  00  00  00  00  00  00
Tags for short granules around the buggy address (one tag corresponds to 16 bytes):
  0xfefcefffeff0: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
=>0xfefceffff000: ..  ..  8c  ..  .. [..] ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
  0xfefceffff010: ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..  ..
See https://clang.llvm.org/docs/HardwareAssistedAddressSanitizerDesign.html#short-granules for a description of short granule tags
Registers where the failure occurred (pc 0xaaaae0ae4a98):
    x0  2c00efdeffff0050  x1  0000000000000004  x2  0000000000000004  x3  0000000000000000
    x4  0000fffefc30ac37  x5  000000000000005d  x6  00000ffffc30ac37  x7  0000efff00000000
    x8  2c00efdeffff0050  x9  0200efff00000000  x10 0000000000000000  x11 0200efff00000000
    x12 0200effe00000310  x13 0200effe00000310  x14 0000000000000008  x15 5d00ffffc30ac360
    x16 0000aaaae0ad062c  x17 0000000000000003  x18 0000000000000001  x19 0000ffffc30ac658
    x20 4e00ffffc30ac6e0  x21 0000aaaae0ac5e10  x22 0000000000000000  x23 0000000000000000
    x24 0000000000000000  x25 0000000000000000  x26 0000000000000000  x27 0000000000000000
    x28 0000000000000000  x29 0000ffffc30ac5a0  x30 0000aaaae0ae4a98
SUMMARY: HWAddressSanitizer: tag-mismatch (/.../main+0x54a94)

LeakSanitizer

LeakSanitizer is run-time memory leak detector.

LeakSanitizer is supported on the following targets:

  • aarch64-apple-darwin
  • aarch64-unknown-linux-gnu
  • x86_64-apple-darwin
  • x86_64-unknown-linux-gnu

See the Clang LeakSanitizer documentation for more details.

MemorySanitizer

MemorySanitizer is detector of uninitialized reads.

MemorySanitizer is supported on the following targets:

  • aarch64-unknown-linux-gnu
  • x86_64-unknown-freebsd
  • x86_64-unknown-linux-gnu

MemorySanitizer requires all program code to be instrumented. C/C++ dependencies need to be recompiled using Clang with -fsanitize=memory option. Failing to achieve that will result in false positive reports.

See the Clang MemorySanitizer documentation for more details.

Example

Detecting the use of uninitialized memory. The -Zbuild-std flag rebuilds and instruments the standard library, and is strictly necessary for the correct operation of the tool. The -Zsanitizer-memory-track-origins enables tracking of the origins of uninitialized memory:

use std::mem::MaybeUninit;

fn main() {
    unsafe {
        let a = MaybeUninit::<[usize; 4]>::uninit();
        let a = a.assume_init();
        println!("{}", a[2]);
    }
}
$ export \
  RUSTFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins' \
  RUSTDOCFLAGS='-Zsanitizer=memory -Zsanitizer-memory-track-origins'
$ cargo clean
$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
==9416==WARNING: MemorySanitizer: use-of-uninitialized-value
    #0 0x560c04f7488a in core::fmt::num::imp::fmt_u64::haa293b0b098501ca $RUST/build/x86_64-unknown-linux-gnu/stage1/lib/rustlib/src/rust/src/libcore/fmt/num.rs:202:16
...
  Uninitialized value was stored to memory at
    #0 0x560c04ae898a in __msan_memcpy.part.0 $RUST/src/llvm-project/compiler-rt/lib/msan/msan_interceptors.cc:1558:3
    #1 0x560c04b2bf88 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:6:16

  Uninitialized value was created by an allocation of 'a' in the stack frame of function '_ZN6memory4main17hd2333c1899d997f5E'
    #0 0x560c04b2bc50 in memory::main::hd2333c1899d997f5 $CWD/src/main.rs:3

MemTagSanitizer

MemTagSanitizer detects a similar class of errors as AddressSanitizer and HardwareAddressSanitizer, but with lower overhead suitable for use as hardening for production binaries.

MemTagSanitizer is supported on the following targets:

  • aarch64-linux-android
  • aarch64-unknown-linux-gnu

MemTagSanitizer requires hardware support and the mte target feature. To enable this target feature compile with -C target-feature="+mte".

See the LLVM MemTagSanitizer documentation for more details.

ShadowCallStack

ShadowCallStack provides backward edge control flow protection by storing a function's return address in a separately allocated 'shadow call stack' and loading the return address from that shadow call stack.

ShadowCallStack requires a platform ABI which reserves x18 as the instrumentation makes use of this register.

ShadowCallStack can be enabled with -Zsanitizer=shadow-call-stack option and is supported on the following targets:

  • aarch64-linux-android

A runtime must be provided by the application or operating system.

See the Clang ShadowCallStack documentation for more details.

ThreadSanitizer

ThreadSanitizer is a data race detection tool. It is supported on the following targets:

  • aarch64-apple-darwin
  • aarch64-unknown-linux-gnu
  • x86_64-apple-darwin
  • x86_64-unknown-freebsd
  • x86_64-unknown-linux-gnu

To work correctly ThreadSanitizer needs to be "aware" of all synchronization operations in a program. It generally achieves that through combination of library interception (for example synchronization performed through pthread_mutex_lock / pthread_mutex_unlock) and compile time instrumentation (e.g. atomic operations). Using it without instrumenting all the program code can lead to false positive reports.

ThreadSanitizer does not support atomic fences std::sync::atomic::fence, nor synchronization performed using inline assembly code.

See the Clang ThreadSanitizer documentation for more details.

Example

static mut A: usize = 0;

fn main() {
    let t = std::thread::spawn(|| {
        unsafe { A += 1 };
    });
    unsafe { A += 1 };

    t.join().unwrap();
}
$ export RUSTFLAGS=-Zsanitizer=thread RUSTDOCFLAGS=-Zsanitizer=thread
$ cargo run -Zbuild-std --target x86_64-unknown-linux-gnu
==================
WARNING: ThreadSanitizer: data race (pid=10574)
  Read of size 8 at 0x5632dfe3d030 by thread T1:
    #0 example::main::_$u7b$$u7b$closure$u7d$$u7d$::h23f64b0b2f8c9484 ../src/main.rs:5:18 (example+0x86cec)
    ...

  Previous write of size 8 at 0x5632dfe3d030 by main thread:
    #0 example::main::h628ffc6626ed85b2 /.../src/main.rs:7:14 (example+0x868c8)
    ...
    #11 main <null> (example+0x86a1a)

  Location is global 'example::A::h43ac149ddf992709' of size 8 at 0x5632dfe3d030 (example+0x000000bd9030)

Instrumentation of external dependencies and std

The sanitizers to varying degrees work correctly with partially instrumented code. On the one extreme is LeakSanitizer that doesn't use any compile time instrumentation, on the other is MemorySanitizer that requires that all program code to be instrumented (failing to achieve that will inevitably result in false positives).

It is strongly recommended to combine sanitizers with recompiled and instrumented standard library, for example using cargo -Zbuild-std functionality.

Build scripts and procedural macros

Use of sanitizers together with build scripts and procedural macros is technically possible, but in almost all cases it would be best avoided. This is especially true for procedural macros which would require an instrumented version of rustc.

In more practical terms when using cargo always remember to pass --target flag, so that rustflags will not be applied to build scripts and procedural macros.

Symbolizing the Reports

Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in PATH.

Additional Information

self-profile


The -Zself-profile compiler flag enables rustc's internal profiler. When enabled, the compiler will output three binary files in the specified directory (or the current working directory if no directory is specified). These files can be analyzed by using the tools in the measureme repository.

To control the data recorded in the trace files, use the -Zself-profile-events flag.

For example:

First, run a compilation session and provide the -Zself-profile flag:

$ rustc --crate-name foo -Zself-profile

This will generate three files in the working directory such as:

  • foo-1234.events
  • foo-1234.string_data
  • foo-1234.string_index

Where foo is the name of the crate and 1234 is the process id of the rustc process.

To get a summary of where the compiler is spending its time:

$ ../measureme/target/release/summarize summarize foo-1234

To generate a flamegraph of the same data:

$ ../measureme/target/release/inferno foo-1234

To dump the event data in a Chromium-profiler compatible format:

$ ../measureme/target/release/crox foo-1234

For more information, consult the measureme documentation.

self-profile-events


The -Zself-profile-events compiler flag controls what events are recorded by the self-profiler when it is enabled via the -Zself-profile flag.

This flag takes a comma delimited list of event types to record.

For example:

$ rustc -Zself-profile -Zself-profile-events=default,args

Event types

  • query-provider

    • Traces each query used internally by the compiler.
  • generic-activity

    • Traces other parts of the compiler not covered by the query system.
  • query-cache-hit

    • Adds tracing information that records when the in-memory query cache is "hit" and does not need to re-execute a query which has been cached.
    • Disabled by default because this significantly increases the trace file size.
  • query-blocked

    • Tracks time that a query tries to run but is blocked waiting on another thread executing the same query to finish executing.
    • Query blocking only occurs when the compiler is built with parallel mode support.
  • incr-cache-load

    • Tracks time that is spent loading and deserializing query results from the incremental compilation on-disk cache.
  • query-keys

    • Adds a serialized representation of each query's query key to the tracing data.
    • Disabled by default because this significantly increases the trace file size.
  • function-args

    • Adds additional tracing data to some generic-activity events.
    • Disabled by default for parity with query-keys.
  • llvm

    • Adds tracing information about LLVM passes and codegeneration.
    • Disabled by default because this only works when -Znew-llvm-pass-manager is enabled.

Event synonyms

  • none

    • Disables all events. Equivalent to the self-profiler being disabled.
  • default

    • The default set of events which stikes a balance between providing detailed tracing data and adding additional overhead to the compilation.
  • args

    • Equivalent to query-keys and function-args.
  • all

    • Enables all events.

Examples

Enable the profiler and capture the default set of events (both invocations are equivalent):

$ rustc -Zself-profile
$ rustc -Zself-profile -Zself-profile-events=default

Enable the profiler and capture the default events and their arguments:

$ rustc -Zself-profile -Zself-profile-events=default,args

src-hash-algorithm

The tracking issue for this feature is: #70401.


The -Z src-hash-algorithm compiler flag controls which algorithm is used when hashing each source file. The hash is stored in the debug info and can be used by a debugger to verify the source code matches the executable.

Supported hash algorithms are: md5, sha1, and sha256. Note that not all hash algorithms are supported by all debug info formats.

By default, the compiler chooses the hash algorithm based on the target specification.

temps-dir


The -Ztemps-dir compiler flag specifies the directory to write the intermediate files in. If not set, the output directory is used. This option is useful if you are running more than one instance of rustc (e.g. with different --crate-type settings), and you need to make sure they are not overwriting each other's intermediate files. No files are kept unless -C save-temps=yes is also set.

tls_model

The tracking issue for this feature is: None.


Option -Z tls-model controls TLS model used to generate code for accessing #[thread_local] static items.

Supported values for this option are:

  • global-dynamic - General Dynamic TLS Model (alternatively called Global Dynamic) is the most general option usable in all circumstances, even if the TLS data is defined in a shared library loaded at runtime and is accessed from code outside of that library. This is the default for most targets.
  • local-dynamic - model usable if the TLS data is only accessed from the shared library or executable it is defined in. The TLS data may be in a library loaded after startup (via dlopen).
  • initial-exec - model usable if the TLS data is defined in the executable or in a shared library loaded at program startup. The TLS data must not be in a library loaded after startup (via dlopen).
  • local-exec - model usable only if the TLS data is defined directly in the executable, but not in a shared library, and is accessed only from that executable.

rustc and LLVM may use a more optimized model than specified if they know that we are producing an executable rather than a library, or that the static item is private enough.

unsound-mir-opts


The -Zunsound-mir-opts compiler flag enables MIR optimization passes which can cause unsound behavior. This flag should only be used by MIR optimization tests in the rustc test suite.

virtual-function-elimination

This option controls whether LLVM runs the Virtual Function Elimination (VFE) optimization. This optimization in only available with LTO, so this flag can only be passed if -Clto is also passed.

VFE makes it possible to remove functions from vtables that are never dynamically called by the rest of the code. Without this flag, LLVM makes the really conservative assumption, that if any function in a vtable is called, no function that is referenced by this vtable can be removed. With this flag additional information are given to LLVM, so that it can determine which functions are actually called and remove the unused functions.

Limitations

At the time of writing this flag may remove vtable functions too eagerly. One such example is in this code:

#![allow(unused)]
fn main() {
trait Foo { fn foo(&self) { println!("foo") } }

impl Foo for usize {}

pub struct FooBox(Box<dyn Foo>);

pub fn make_foo() -> FooBox { FooBox(Box::new(0)) }

#[inline]
pub fn f(a: FooBox) { a.0.foo() }
}

In the above code the Foo trait is private, so an assumption is made that its functions can only be seen/called from the current crate and can therefore get optimized out, if unused. However, with make_foo you can produce a wrapped dyn Foo type outside of the current crate, which can then be used in f. Due to inlining of f, Foo::foo can then be called from a foreign crate. This can lead to miscompilations.

Language features

aarch64_ver_target_feature

The tracking issue for this feature is: #44839


abi_amdgpu_kernel

The tracking issue for this feature is: #51575


abi_avr_interrupt

The tracking issue for this feature is: #69664


abi_c_cmse_nonsecure_call

The tracking issue for this feature is: #81391


The TrustZone-M feature is available for targets with the Armv8-M architecture profile (thumbv8m in their target name). LLVM, the Rust compiler and the linker are providing support for the TrustZone-M feature.

One of the things provided, with this unstable feature, is the C-cmse-nonsecure-call function ABI. This ABI is used on function pointers to non-secure code to mark a non-secure function call (see section 5.5 for details).

With this ABI, the compiler will do the following to perform the call:

  • save registers needed after the call to Secure memory
  • clear all registers that might contain confidential information
  • clear the Least Significant Bit of the function address
  • branches using the BLXNS instruction

To avoid using the non-secure stack, the compiler will constrain the number and type of parameters/return value.

The extern "C-cmse-nonsecure-call" ABI is otherwise equivalent to the extern "C" ABI.

#![no_std]
#![feature(abi_c_cmse_nonsecure_call)]

#[no_mangle]
pub fn call_nonsecure_function(addr: usize) -> u32 {
    let non_secure_function =
        unsafe { core::mem::transmute::<usize, extern "C-cmse-nonsecure-call" fn() -> u32>(addr) };
    non_secure_function()
}
$ rustc --emit asm --crate-type lib --target thumbv8m.main-none-eabi function.rs

call_nonsecure_function:
        .fnstart
        .save   {r7, lr}
        push    {r7, lr}
        .setfp  r7, sp
        mov     r7, sp
        .pad    #16
        sub     sp, #16
        str     r0, [sp, #12]
        ldr     r0, [sp, #12]
        str     r0, [sp, #8]
        b       .LBB0_1
.LBB0_1:
        ldr     r0, [sp, #8]
        push.w  {r4, r5, r6, r7, r8, r9, r10, r11}
        bic     r0, r0, #1
        mov     r1, r0
        mov     r2, r0
        mov     r3, r0
        mov     r4, r0
        mov     r5, r0
        mov     r6, r0
        mov     r7, r0
        mov     r8, r0
        mov     r9, r0
        mov     r10, r0
        mov     r11, r0
        mov     r12, r0
        msr     apsr_nzcvq, r0
        blxns   r0
        pop.w   {r4, r5, r6, r7, r8, r9, r10, r11}
        str     r0, [sp, #4]
        b       .LBB0_2
.LBB0_2:
        ldr     r0, [sp, #4]
        add     sp, #16
        pop     {r7, pc}

abi_efiapi

The tracking issue for this feature is: #65815


abi_msp430_interrupt

The tracking issue for this feature is: #38487


In the MSP430 architecture, interrupt handlers have a special calling convention. You can use the "msp430-interrupt" ABI to make the compiler apply the right calling convention to the interrupt handlers you define.

#![feature(abi_msp430_interrupt)]
#![no_std]

// Place the interrupt handler at the appropriate memory address
// (Alternatively, you can use `#[used]` and remove `pub` and `#[no_mangle]`)
#[link_section = "__interrupt_vector_10"]
#[no_mangle]
pub static TIM0_VECTOR: extern "msp430-interrupt" fn() = tim0;

// The interrupt handler
extern "msp430-interrupt" fn tim0() {
    // ..
}
$ msp430-elf-objdump -CD ./target/msp430/release/app
Disassembly of section __interrupt_vector_10:

0000fff2 <TIM0_VECTOR>:
    fff2:       00 c0           interrupt service routine at 0xc000

Disassembly of section .text:

0000c000 <int::tim0>:
    c000:       00 13           reti

abi_ptx

The tracking issue for this feature is: #38788


When emitting PTX code, all vanilla Rust functions (fn) get translated to "device" functions. These functions are not callable from the host via the CUDA API so a crate with only device functions is not too useful!

OTOH, "global" functions can be called by the host; you can think of them as the real public API of your crate. To produce a global function use the "ptx-kernel" ABI.

#![feature(abi_ptx)]
#![no_std]

pub unsafe extern "ptx-kernel" fn global_function() {
    device_function();
}

pub fn device_function() {
    // ..
}
$ xargo rustc --target nvptx64-nvidia-cuda --release -- --emit=asm

$ cat $(find -name '*.s')
//
// Generated by LLVM NVPTX Back-End
//

.version 3.2
.target sm_20
.address_size 64

        // .globl       _ZN6kernel15global_function17h46111ebe6516b382E

.visible .entry _ZN6kernel15global_function17h46111ebe6516b382E()
{


        ret;
}

        // .globl       _ZN6kernel15device_function17hd6a0e4993bbf3f78E
.visible .func _ZN6kernel15device_function17hd6a0e4993bbf3f78E()
{


        ret;
}

abi_thiscall

The tracking issue for this feature is: #42202


The MSVC ABI on x86 Windows uses the thiscall calling convention for C++ instance methods by default; it is identical to the usual (C) calling convention on x86 Windows except that the first parameter of the method, the this pointer, is passed in the ECX register.

abi_unadjusted

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


abi_vectorcall

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


abi_x86_interrupt

The tracking issue for this feature is: #40180


adt_const_params

The tracking issue for this feature is: #95174


alloc_error_handler

The tracking issue for this feature is: #51540


allocator_internals

This feature does not have a tracking issue, it is an unstable implementation detail of the global_allocator feature not intended for use outside the compiler.


allow_internal_unsafe

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


allow_internal_unstable

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


anonymous_lifetime_in_impl_trait

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


arbitrary_enum_discriminant

The tracking issue for this feature is: #60553


The arbitrary_enum_discriminant feature permits tuple-like and struct-like enum variants with #[repr(<int-type>)] to have explicit discriminants.

Examples

#![allow(unused)]
#![feature(arbitrary_enum_discriminant)]

fn main() {
#[allow(dead_code)]
#[repr(u8)]
enum Enum {
    Unit = 3,
    Tuple(u16) = 2,
    Struct {
        a: u8,
        b: u16,
    } = 1,
}

impl Enum {
    fn tag(&self) -> u8 {
        unsafe { *(self as *const Self as *const u8) }
    }
}

assert_eq!(3, Enum::Unit.tag());
assert_eq!(2, Enum::Tuple(5).tag());
assert_eq!(1, Enum::Struct{a: 7, b: 11}.tag());
}

arbitrary_self_types

The tracking issue for this feature is: #44874


arm_target_feature

The tracking issue for this feature is: #44839


asm_const

The tracking issue for this feature is: #93332


This feature adds a const <expr> operand type to asm! and global_asm!.

  • <expr> must be an integer constant expression.
  • The value of the expression is formatted as a string and substituted directly into the asm template string.

asm_experimental_arch

The tracking issue for this feature is: #93335


This feature tracks asm! and global_asm! support for the following architectures:

  • NVPTX
  • PowerPC
  • Hexagon
  • MIPS32r2 and MIPS64r2
  • wasm32
  • BPF
  • SPIR-V
  • AVR
  • MSP430

Register classes

ArchitectureRegister classRegistersLLVM constraint code
MIPSreg$[2-25]r
MIPSfreg$f[0-31]f
NVPTXreg16None*h
NVPTXreg32None*r
NVPTXreg64None*l
Hexagonregr[0-28]r
PowerPCregr[0-31]r
PowerPCreg_nonzeror[1-31]b
PowerPCfregf[0-31]f
PowerPCcrcr[0-7], crOnly clobbers
PowerPCxerxerOnly clobbers
wasm32localNone*r
BPFregr[0-10]r
BPFwregw[0-10]w
AVRregr[2-25], XH, XL, ZH, ZLr
AVRreg_upperr[16-25], XH, XL, ZH, ZLd
AVRreg_pairr3r2 .. r25r24, X, Zr
AVRreg_iwr25r24, X, Zw
AVRreg_ptrX, Ze
MSP430regr[0-15]r

Notes:

  • NVPTX doesn't have a fixed register set, so named registers are not supported.

  • WebAssembly doesn't have registers, so named registers are not supported.

Register class supported types

ArchitectureRegister classTarget featureAllowed types
MIPS32regNonei8, i16, i32, f32
MIPS32fregNonef32, f64
MIPS64regNonei8, i16, i32, i64, f32, f64
MIPS64fregNonef32, f64
NVPTXreg16Nonei8, i16
NVPTXreg32Nonei8, i16, i32, f32
NVPTXreg64Nonei8, i16, i32, f32, i64, f64
HexagonregNonei8, i16, i32, f32
PowerPCregNonei8, i16, i32
PowerPCreg_nonzeroNonei8, i16, i32
PowerPCfregNonef32, f64
PowerPCcrN/AOnly clobbers
PowerPCxerN/AOnly clobbers
wasm32localNonei8 i16 i32 i64 f32 f64
BPFregNonei8 i16 i32 i64
BPFwregalu32i8 i16 i32
AVRreg, reg_upperNonei8
AVRreg_pair, reg_iw, reg_ptrNonei16
MSP430regNonei8, i16

Register aliases

ArchitectureBase registerAliases
Hexagonr29sp
Hexagonr30fr
Hexagonr31lr
BPFr[0-10]w[0-10]
AVRXHr27
AVRXLr26
AVRZHr31
AVRZLr30
MSP430r0pc
MSP430r1sp
MSP430r2sr
MSP430r3cg
MSP430r4fp

Notes:

  • TI does not mandate a frame pointer for MSP430, but toolchains are allowed to use one; LLVM uses r4.

Unsupported registers

ArchitectureUnsupported registerReason
AllspThe stack pointer must be restored to its original value at the end of an asm code block.
Allfr (Hexagon), $fp (MIPS), Y (AVR), r4 (MSP430)The frame pointer cannot be used as an input or output.
Allr19 (Hexagon)This is used internally by LLVM as a "base pointer" for functions with complex stack frames.
MIPS$0 or $zeroThis is a constant zero register which can't be modified.
MIPS$1 or $atReserved for assembler.
MIPS$26/$k0, $27/$k1OS-reserved registers.
MIPS$28/$gpGlobal pointer cannot be used as inputs or outputs.
MIPS$raReturn address cannot be used as inputs or outputs.
HexagonlrThis is the link register which cannot be used as an input or output.
AVRr0, r1, r1r0Due to an issue in LLVM, the r0 and r1 registers cannot be used as inputs or outputs. If modified, they must be restored to their original values before the end of the block.
MSP430r0, r2, r3These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to.

Template modifiers

ArchitectureRegister classModifierExample outputLLVM modifier
MIPSregNone$2None
MIPSfregNone$f0None
NVPTXreg16Noners0None
NVPTXreg32Noner0None
NVPTXreg64Nonerd0None
HexagonregNoner0None
PowerPCregNone0None
PowerPCreg_nonzeroNone3b
PowerPCfregNone0None

Flags covered by preserves_flags

These flags registers must be restored upon exiting the asm block if the preserves_flags option is set:

  • AVR
    • The status register SREG.
  • MSP430
    • The status register r2.

asm_sym

The tracking issue for this feature is: #93333


This feature adds a sym <path> operand type to asm! and global_asm!.

  • <path> must refer to a fn or static.
  • A mangled symbol name referring to the item is substituted into the asm template string.
  • The substituted string does not include any modifiers (e.g. GOT, PLT, relocations, etc).
  • <path> is allowed to point to a #[thread_local] static, in which case the asm code can combine the symbol with relocations (e.g. @plt, @TPOFF) to read from thread-local data.

asm_unwind

The tracking issue for this feature is: #93334


This feature adds a may_unwind option to asm! which allows an asm block to unwind stack and be part of the stack unwinding process. This option is only supported by the LLVM backend right now.

associated_const_equality

The tracking issue for this feature is: #92827


associated_type_bounds

The tracking issue for this feature is: #52662


associated_type_defaults

The tracking issue for this feature is: #29661


async_closure

The tracking issue for this feature is: #62290


auto_traits

The tracking issue for this feature is #13231


The auto_traits feature gate allows you to define auto traits.

Auto traits, like Send or Sync in the standard library, are marker traits that are automatically implemented for every type, unless the type, or a type it contains, has explicitly opted out via a negative impl. (Negative impls are separately controlled by the negative_impls feature.)

impl !Trait for Type {}

Example:

#![feature(negative_impls)]
#![feature(auto_traits)]

auto trait Valid {}

struct True;
struct False;

impl !Valid for False {}

struct MaybeValid<T>(T);

fn must_be_valid<T: Valid>(_t: T) { }

fn main() {
    // works
    must_be_valid( MaybeValid(True) );

    // compiler error - trait bound not satisfied
    // must_be_valid( MaybeValid(False) );
}

Automatic trait implementations

When a type is declared as an auto trait, we will automatically create impls for every struct/enum/union, unless an explicit impl is provided. These automatic impls contain a where clause for each field of the form T: AutoTrait, where T is the type of the field and AutoTrait is the auto trait in question. As an example, consider the struct List and the auto trait Send:

#![allow(unused)]
fn main() {
struct List<T> {
  data: T,
  next: Option<Box<List<T>>>,
}
}

Presuming that there is no explicit impl of Send for List, the compiler will supply an automatic impl of the form:

#![allow(unused)]
fn main() {
struct List<T> {
  data: T,
  next: Option<Box<List<T>>>,
}

unsafe impl<T> Send for List<T>
where
  T: Send, // from the field `data`
  Option<Box<List<T>>>: Send, // from the field `next`
{ }
}

Explicit impls may be either positive or negative. They take the form:

impl<...> AutoTrait for StructName<..> { }
impl<...> !AutoTrait for StructName<..> { }

Coinduction: Auto traits permit cyclic matching

Unlike ordinary trait matching, auto traits are coinductive. This means, in short, that cycles which occur in trait matching are considered ok. As an example, consider the recursive struct List introduced in the previous section. In attempting to determine whether List: Send, we would wind up in a cycle: to apply the impl, we must show that Option<Box<List>>: Send, which will in turn require Box<List>: Send and then finally List: Send again. Under ordinary trait matching, this cycle would be an error, but for an auto trait it is considered a successful match.

Items

Auto traits cannot have any trait items, such as methods or associated types. This ensures that we can generate default implementations.

Supertraits

Auto traits cannot have supertraits. This is for soundness reasons, as the interaction of coinduction with implied bounds is difficult to reconcile.

avx512_target_feature

The tracking issue for this feature is: #44839


box_patterns

The tracking issue for this feature is: #29641

See also box_syntax


Box patterns let you match on Box<T>s:

#![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!()
    }
}

box_syntax

The tracking issue for this feature is: #49733

See also box_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 create a Box. An example usage would be:

#![feature(box_syntax)]

fn main() {
    let b = box 5;
}

bpf_target_feature

The tracking issue for this feature is: #44839


c_unwind

The tracking issue for this feature is: #74990


Introduces new ABI strings:

  • "C-unwind"
  • "cdecl-unwind"
  • "stdcall-unwind"
  • "fastcall-unwind"
  • "vectorcall-unwind"
  • "thiscall-unwind"
  • "aapcs-unwind"
  • "win64-unwind"
  • "sysv64-unwind"
  • "system-unwind"

These enable unwinding from other languages (such as C++) into Rust frames and from Rust into other languages.

See RFC 2945 for more information.

c_variadic

The tracking issue for this feature is: #44930


The c_variadic language feature enables C-variadic functions to be defined in Rust. They may be called both from within Rust and via FFI.

Examples

#![allow(unused)]
#![feature(c_variadic)]

fn main() {
pub unsafe extern "C" fn add(n: usize, mut args: ...) -> usize {
    let mut sum = 0;
    for _ in 0..n {
        sum += args.arg::<usize>();
    }
    sum
}
}

capture_disjoint_fields

The tracking issue for this feature is: #53488


cfg_sanitize

The tracking issue for this feature is: #39699


The cfg_sanitize feature makes it possible to execute different code depending on whether a particular sanitizer is enabled or not.

Examples

#![allow(unused)]
#![feature(cfg_sanitize)]

fn main() {
#[cfg(sanitize = "thread")]
fn a() {
    // ...
}

#[cfg(not(sanitize = "thread"))]
fn a() {
    // ...
}

fn b() {
    if cfg!(sanitize = "leak") {
        // ...
    } else {
        // ...
    }
}
}

cfg_target_abi

The tracking issue for this feature is: #80970


cfg_target_compact

The tracking issue for this feature is: #96901


cfg_target_has_atomic

The tracking issue for this feature is: #94039


cfg_target_has_atomic_equal_alignment

The tracking issue for this feature is: #93822


cfg_target_thread_local

The tracking issue for this feature is: #29594


cfg_version

The tracking issue for this feature is: #64796


The cfg_version feature makes it possible to execute different code depending on the compiler version. It will return true if the compiler version is greater than or equal to the specified version.

Examples

#![allow(unused)]
#![feature(cfg_version)]

fn main() {
#[cfg(version("1.42"))] // 1.42 and above
fn a() {
    // ...
}

#[cfg(not(version("1.42")))] // 1.41 and below
fn a() {
    // ...
}

fn b() {
    if cfg!(version("1.42")) {
        // ...
    } else {
        // ...
    }
}
}

closure_lifetime_binder

The tracking issue for this feature is: #97362


closure_track_caller

The tracking issue for this feature is: #87417


Allows using the #[track_caller] attribute on closures and generators. Calls made to the closure or generator will have caller information available through std::panic::Location::caller(), just like using #[track_caller] on a function.

cmpxchg16b_target_feature

The tracking issue for this feature is: #44839


cmse_nonsecure_entry

The tracking issue for this feature is: #75835


The TrustZone-M feature is available for targets with the Armv8-M architecture profile (thumbv8m in their target name). LLVM, the Rust compiler and the linker are providing support for the TrustZone-M feature.

One of the things provided, with this unstable feature, is the cmse_nonsecure_entry attribute. This attribute marks a Secure function as an entry function (see section 5.4 for details). With this attribute, the compiler will do the following:

  • add a special symbol on the function which is the __acle_se_ prefix and the standard function name
  • constrain the number of parameters to avoid using the Non-Secure stack
  • before returning from the function, clear registers that might contain Secure information
  • use the BXNS instruction to return

Because the stack can not be used to pass parameters, there will be compilation errors if:

  • the total size of all parameters is too big (for example more than four 32 bits integers)
  • the entry function is not using a C ABI

The special symbol __acle_se_ will be used by the linker to generate a secure gateway veneer.

#![feature(cmse_nonsecure_entry)]

#[no_mangle]
#[cmse_nonsecure_entry]
pub extern "C" fn entry_function(input: u32) -> u32 {
    input + 6
}
$ rustc --emit obj --crate-type lib --target thumbv8m.main-none-eabi function.rs
$ arm-none-eabi-objdump -D function.o

00000000 <entry_function>:
   0:   b580            push    {r7, lr}
   2:   466f            mov     r7, sp
   4:   b082            sub     sp, #8
   6:   9001            str     r0, [sp, #4]
   8:   1d81            adds    r1, r0, #6
   a:   460a            mov     r2, r1
   c:   4281            cmp     r1, r0
   e:   9200            str     r2, [sp, #0]
  10:   d30b            bcc.n   2a <entry_function+0x2a>
  12:   e7ff            b.n     14 <entry_function+0x14>
  14:   9800            ldr     r0, [sp, #0]
  16:   b002            add     sp, #8
  18:   e8bd 4080       ldmia.w sp!, {r7, lr}
  1c:   4671            mov     r1, lr
  1e:   4672            mov     r2, lr
  20:   4673            mov     r3, lr
  22:   46f4            mov     ip, lr
  24:   f38e 8800       msr     CPSR_f, lr
  28:   4774            bxns    lr
  2a:   f240 0000       movw    r0, #0
  2e:   f2c0 0000       movt    r0, #0
  32:   f240 0200       movw    r2, #0
  36:   f2c0 0200       movt    r2, #0
  3a:   211c            movs    r1, #28
  3c:   f7ff fffe       bl      0 <_ZN4core9panicking5panic17h5c028258ca2fb3f5E>
  40:   defe            udf     #254    ; 0xfe

collapse_debuginfo

The tracking issue for this feature is: #100758


compiler_builtins

This feature is internal to the Rust compiler and is not intended for general use.


const_async_blocks

The tracking issue for this feature is: #85368


const_eval_limit

The tracking issue for this feature is: #67217

The const_eval_limit allows someone to limit the evaluation steps the CTFE undertakes to evaluate a const fn.

const_extern_fn

The tracking issue for this feature is: #64926


const_fn_floating_point_arithmetic

The tracking issue for this feature is: #57241


const_for

The tracking issue for this feature is: #87575


const_mut_refs

The tracking issue for this feature is: #57349


const_precise_live_drops

The tracking issue for this feature is: #73255


const_refs_to_cell

The tracking issue for this feature is: #80384


const_trait_impl

The tracking issue for this feature is: #67792


const_try

The tracking issue for this feature is: #74935


custom_inner_attributes

The tracking issue for this feature is: #54726


custom_test_frameworks

The tracking issue for this feature is: #50297


The custom_test_frameworks feature allows the use of #[test_case] and #![test_runner]. Any function, const, or static can be annotated with #[test_case] causing it to be aggregated (like #[test]) and be passed to the test runner determined by the #![test_runner] crate attribute.

#![allow(unused)]
#![feature(custom_test_frameworks)]
#![test_runner(my_runner)]

fn main() {
fn my_runner(tests: &[&i32]) {
    for t in tests {
        if **t == 0 {
            println!("PASSED");
        } else {
            println!("FAILED");
        }
    }
}

#[test_case]
const WILL_PASS: i32 = 0;

#[test_case]
const WILL_FAIL: i32 = 4;
}

debugger_visualizer

The tracking issue for this feature is: #95939


The debugger_visualizer attribute can be used to instruct the compiler to embed a debugger visualizer file into the PDB/ELF generated by rustc.

Examples

#![feature(debugger_visualizer)]
#![debugger_visualizer(natvis_file = "foo.natvis")]
#![debugger_visualizer(gdb_script_file = "foo.py")]
struct Foo {

}

Limitations

Currently, this feature only supports embedding Natvis files on -windows-msvc targets via the natvis_file meta item. -windows-gnu targets are not currently supported.

decl_macro

The tracking issue for this feature is: #39412


default_alloc_error_handler

The tracking issue for this feature is: #66741


default_type_parameter_fallback

The tracking issue for this feature is: #27336


deprecated_safe

The tracking issue for this feature is: #94978


deprecated_suggestion

The tracking issue for this feature is: #94785


doc_auto_cfg

The tracking issue for this feature is: #43781


doc_cfg

The tracking issue for this feature is: #43781


The doc_cfg feature allows an API be documented as only available in some specific platforms. This attribute has two effects:

  1. In the annotated item's documentation, there will be a message saying "Available on (platform) only".

  2. The item's doc-tests will only run on the specific platform.

In addition to allowing the use of the #[doc(cfg)] attribute, this feature enables the use of a special conditional compilation flag, #[cfg(doc)], set whenever building documentation on your crate.

This feature was introduced as part of PR #43348 to allow the platform-specific parts of the standard library be documented.

#![allow(unused)]
#![feature(doc_cfg)]

fn main() {
#[cfg(any(windows, doc))]
#[doc(cfg(windows))]
/// The application's icon in the notification area (a.k.a. system tray).
///
/// # Examples
///
/// ```no_run
/// extern crate my_awesome_ui_library;
/// use my_awesome_ui_library::current_app;
/// use my_awesome_ui_library::windows::notification;
///
/// let icon = current_app().get::<notification::Icon>();
/// icon.show();
/// icon.show_message("Hello");
/// ```
pub struct Icon {
    // ...
}
}

doc_cfg_hide

The tracking issue for this feature is: #43781


doc_masked

The tracking issue for this feature is: #44027


The doc_masked feature allows a crate to exclude types from a given crate from appearing in lists of trait implementations. The specifics of the feature are as follows:

  1. When rustdoc encounters an extern crate statement annotated with a #[doc(masked)] attribute, it marks the crate as being masked.

  2. When listing traits a given type implements, rustdoc ensures that traits from masked crates are not emitted into the documentation.

  3. When listing types that implement a given trait, rustdoc ensures that types from masked crates are not emitted into the documentation.

This feature was introduced in PR #44026 to ensure that compiler-internal and implementation-specific types and traits were not included in the standard library's documentation. Such types would introduce broken links into the documentation.

doc_notable_trait

The tracking issue for this feature is: #45040

The doc_notable_trait feature allows the use of the #[doc(notable_trait)] attribute, which will display the trait in a "Notable traits" dialog for functions returning types that implement the trait. For example, this attribute is applied to the Iterator, Future, io::Read, and io::Write traits in the standard library.

You can do this on your own traits like so:

#![feature(doc_notable_trait)]

#[doc(notable_trait)]
pub trait MyTrait {}

pub struct MyStruct;
impl MyTrait for MyStruct {}

/// The docs for this function will have a button that displays a dialog about
/// `MyStruct` implementing `MyTrait`.
pub fn my_fn() -> MyStruct { MyStruct }

This feature was originally implemented in PR #45039.

See also its documentation in the rustdoc book.

dropck_eyepatch

The tracking issue for this feature is: #34761


ermsb_target_feature

The tracking issue for this feature is: #44839


exclusive_range_pattern

The tracking issue for this feature is: #37854.


The exclusive_range_pattern feature allows non-inclusive range patterns (0..10) to be used in appropriate pattern matching contexts. It also can be combined with #![feature(half_open_range_patterns] to be able to use RangeTo patterns (..10).

It also enabled RangeFrom patterns but that has since been stabilized.

#![allow(unused)]
#![feature(exclusive_range_pattern)]
fn main() {
    let x = 5;
    match x {
        0..10 => println!("single digit"),
        10 => println!("ten isn't part of the above range"),
        _ => println!("nor is everything else.")
    }
}

exhaustive_patterns

The tracking issue for this feature is: #51085


extern_types

The tracking issue for this feature is: #43467


f16c_target_feature

The tracking issue for this feature is: #44839


ffi_const

The tracking issue for this feature is: #58328


The #[ffi_const] attribute applies clang's const attribute to foreign functions declarations.

That is, #[ffi_const] functions shall have no effects except for its return value, which can only depend on the values of the function parameters, and is not affected by changes to the observable state of the program.

Applying the #[ffi_const] attribute to a function that violates these requirements is undefined behaviour.

This attribute enables Rust to perform common optimizations, like sub-expression elimination, and it can avoid emitting some calls in repeated invocations of the function with the same argument values regardless of other operations being performed in between these functions calls (as opposed to #[ffi_pure] functions).

Pitfalls

A #[ffi_const] function can only read global memory that would not affect its return value for the whole execution of the program (e.g. immutable global memory). #[ffi_const] functions are referentially-transparent and therefore more strict than #[ffi_pure] functions.

A common pitfall involves applying the #[ffi_const] attribute to a function that reads memory through pointer arguments which do not necessarily point to immutable global memory.

A #[ffi_const] function that returns unit has no effect on the abstract machine's state, and a #[ffi_const] function cannot be #[ffi_pure].

A #[ffi_const] function must not diverge, neither via a side effect (e.g. a call to abort) nor by infinite loops.

When translating C headers to Rust FFI, it is worth verifying for which targets the const attribute is enabled in those headers, and using the appropriate cfg macros in the Rust side to match those definitions. While the semantics of const are implemented identically by many C and C++ compilers, e.g., clang, GCC, ARM C/C++ compiler, IBM ILE C/C++, etc. they are not necessarily implemented in this way on all of them. It is therefore also worth verifying that the semantics of the C toolchain used to compile the binary being linked against are compatible with those of the #[ffi_const].

ffi_pure

The tracking issue for this feature is: #58329


The #[ffi_pure] attribute applies clang's pure attribute to foreign functions declarations.

That is, #[ffi_pure] functions shall have no effects except for its return value, which shall not change across two consecutive function calls with the same parameters.

Applying the #[ffi_pure] attribute to a function that violates these requirements is undefined behavior.

This attribute enables Rust to perform common optimizations, like sub-expression elimination and loop optimizations. Some common examples of pure functions are strlen or memcmp.

These optimizations are only applicable when the compiler can prove that no program state observable by the #[ffi_pure] function has changed between calls of the function, which could alter the result. See also the #[ffi_const] attribute, which provides stronger guarantees regarding the allowable behavior of a function, enabling further optimization.

Pitfalls

A #[ffi_pure] function can read global memory through the function parameters (e.g. pointers), globals, etc. #[ffi_pure] functions are not referentially-transparent, and are therefore more relaxed than #[ffi_const] functions.

However, accessing global memory through volatile or atomic reads can violate the requirement that two consecutive function calls shall return the same value.

A pure function that returns unit has no effect on the abstract machine's state.

A #[ffi_pure] function must not diverge, neither via a side effect (e.g. a call to abort) nor by infinite loops.

When translating C headers to Rust FFI, it is worth verifying for which targets the pure attribute is enabled in those headers, and using the appropriate cfg macros in the Rust side to match those definitions. While the semantics of pure are implemented identically by many C and C++ compilers, e.g., clang, GCC, ARM C/C++ compiler, IBM ILE C/C++, etc. they are not necessarily implemented in this way on all of them. It is therefore also worth verifying that the semantics of the C toolchain used to compile the binary being linked against are compatible with those of the #[ffi_pure].

ffi_returns_twice

The tracking issue for this feature is: #58314


fn_align

The tracking issue for this feature is: #82232


fundamental

The tracking issue for this feature is: #29635


generator_clone

The tracking issue for this feature is: #95360


generators

The tracking issue for this feature is: #43122


The generators feature gate in Rust allows you to define generator or coroutine literals. A generator is a "resumable function" that syntactically resembles a closure but compiles to much different semantics in the compiler itself. The primary feature of a generator is that it can be suspended during execution to be resumed at a later date. Generators use the yield keyword to "return", and then the caller can resume a generator to resume execution just after the yield keyword.

Generators are an extra-unstable feature in the compiler right now. Added in RFC 2033 they're mostly intended right now as a information/constraint gathering phase. The intent is that experimentation can happen on the nightly compiler before actual stabilization. A further RFC will be required to stabilize generators/coroutines and will likely contain at least a few small tweaks to the overall design.

A syntactical example of a generator is:

#![feature(generators, generator_trait)]

use std::ops::{Generator, GeneratorState};
use std::pin::Pin;

fn main() {
    let mut generator = || {
        yield 1;
        return "foo"
    };

    match Pin::new(&mut generator).resume(()) {
        GeneratorState::Yielded(1) => {}
        _ => panic!("unexpected value from resume"),
    }
    match Pin::new(&mut generator).resume(()) {
        GeneratorState::Complete("foo") => {}
        _ => panic!("unexpected value from resume"),
    }
}

Generators are closure-like literals which can contain a yield statement. The yield statement takes an optional expression of a value to yield out of the generator. All generator literals implement the Generator trait in the std::ops module. The Generator trait has one main method, resume, which resumes execution of the generator at the previous suspension point.

An example of the control flow of generators is that the following example prints all numbers in order:

#![feature(generators, generator_trait)]

use std::ops::Generator;
use std::pin::Pin;

fn main() {
    let mut generator = || {
        println!("2");
        yield;
        println!("4");
    };

    println!("1");
    Pin::new(&mut generator).resume(());
    println!("3");
    Pin::new(&mut generator).resume(());
    println!("5");
}

At this time the main intended use case of generators is an implementation primitive for async/await syntax, but generators will likely be extended to ergonomic implementations of iterators and other primitives in the future. Feedback on the design and usage is always appreciated!

The Generator trait

The Generator trait in std::ops currently looks like:

#![allow(unused)]
fn main() {
#![feature(arbitrary_self_types, generator_trait)]
use std::ops::GeneratorState;
use std::pin::Pin;

pub trait Generator<R = ()> {
    type Yield;
    type Return;
    fn resume(self: Pin<&mut Self>, resume: R) -> GeneratorState<Self::Yield, Self::Return>;
}
}

The Generator::Yield type is the type of values that can be yielded with the yield statement. The Generator::Return type is the returned type of the generator. This is typically the last expression in a generator's definition or any value passed to return in a generator. The resume function is the entry point for executing the Generator itself.

The return value of resume, GeneratorState, looks like:

#![allow(unused)]
fn main() {
pub enum GeneratorState<Y, R> {
    Yielded(Y),
    Complete(R),
}
}

The Yielded variant indicates that the generator can later be resumed. This corresponds to a yield point in a generator. The Complete variant indicates that the generator is complete and cannot be resumed again. Calling resume after a generator has returned Complete will likely result in a panic of the program.

Closure-like semantics

The closure-like syntax for generators alludes to the fact that they also have closure-like semantics. Namely:

  • When created, a generator executes no code. A closure literal does not actually execute any of the closure's code on construction, and similarly a generator literal does not execute any code inside the generator when constructed.

  • Generators can capture outer variables by reference or by move, and this can be tweaked with the move keyword at the beginning of the closure. Like closures all generators will have an implicit environment which is inferred by the compiler. Outer variables can be moved into a generator for use as the generator progresses.

  • Generator literals produce a value with a unique type which implements the std::ops::Generator trait. This allows actual execution of the generator through the Generator::resume method as well as also naming it in return types and such.

  • Traits like Send and Sync are automatically implemented for a Generator depending on the captured variables of the environment. Unlike closures, generators also depend on variables live across suspension points. This means that although the ambient environment may be Send or Sync, the generator itself may not be due to internal variables live across yield points being not-Send or not-Sync. Note that generators do not implement traits like Copy or Clone automatically.

  • Whenever a generator is dropped it will drop all captured environment variables.

Generators as state machines

In the compiler, generators are currently compiled as state machines. Each yield expression will correspond to a different state that stores all live variables over that suspension point. Resumption of a generator will dispatch on the current state and then execute internally until a yield is reached, at which point all state is saved off in the generator and a value is returned.

Let's take a look at an example to see what's going on here:

#![feature(generators, generator_trait)]

use std::ops::Generator;
use std::pin::Pin;

fn main() {
    let ret = "foo";
    let mut generator = move || {
        yield 1;
        return ret
    };

    Pin::new(&mut generator).resume(());
    Pin::new(&mut generator).resume(());
}

This generator literal will compile down to something similar to:

#![feature(arbitrary_self_types, generators, generator_trait)]

use std::ops::{Generator, GeneratorState};
use std::pin::Pin;

fn main() {
    let ret = "foo";
    let mut generator = {
        enum __Generator {
            Start(&'static str),
            Yield1(&'static str),
            Done,
        }

        impl Generator for __Generator {
            type Yield = i32;
            type Return = &'static str;

            fn resume(mut self: Pin<&mut Self>, resume: ()) -> GeneratorState<i32, &'static str> {
                use std::mem;
                match mem::replace(&mut *self, __Generator::Done) {
                    __Generator::Start(s) => {
                        *self = __Generator::Yield1(s);
                        GeneratorState::Yielded(1)
                    }

                    __Generator::Yield1(s) => {
                        *self = __Generator::Done;
                        GeneratorState::Complete(s)
                    }

                    __Generator::Done => {
                        panic!("generator resumed after completion")
                    }
                }
            }
        }

        __Generator::Start(ret)
    };

    Pin::new(&mut generator).resume(());
    Pin::new(&mut generator).resume(());
}

Notably here we can see that the compiler is generating a fresh type, __Generator in this case. This type has a number of states (represented here as an enum) corresponding to each of the conceptual states of the generator. At the beginning we're closing over our outer variable foo and then that variable is also live over the yield point, so it's stored in both states.

When the generator starts it'll immediately yield 1, but it saves off its state just before it does so indicating that it has reached the yield point. Upon resuming again we'll execute the return ret which returns the Complete state.

Here we can also note that the Done state, if resumed, panics immediately as it's invalid to resume a completed generator. It's also worth noting that this is just a rough desugaring, not a normative specification for what the compiler does.

generic_arg_infer

The tracking issue for this feature is: #85077


generic_assert

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


generic_associated_types_extended

The tracking issue for this feature is: #95451


generic_const_exprs

The tracking issue for this feature is: #76560


half_open_range_patterns

The tracking issue for this feature is: #67264 It is part of the #![exclusive_range_pattern] feature, tracked at #37854.


The half_open_range_patterns feature allows RangeTo patterns (..10) to be used in appropriate pattern matching contexts. This requires also enabling the exclusive_range_pattern feature.

It also enabled RangeFrom patterns but that has since been stabilized.

#![allow(unused)]
#![feature(half_open_range_patterns)]
#![feature(exclusive_range_pattern)]
fn main() {
    let x = 5;
    match x {
        ..0 => println!("negative!"), // "RangeTo" pattern. Unstable.
        0 => println!("zero!"),
        1.. => println!("positive!"), // "RangeFrom" pattern. Stable.
    }
}

hexagon_target_feature

The tracking issue for this feature is: #44839


if_let_guard

The tracking issue for this feature is: #51114


imported_main

The tracking issue for this feature is: #28937


inherent_associated_types

The tracking issue for this feature is: #8995


inline_const

The tracking issue for this feature is: #76001

See also inline_const_pat


This feature allows you to use inline constant expressions. For example, you can turn this code:

fn add_one(x: i32) -> i32 { x + 1 }
const MY_COMPUTATION: i32 = 1 + 2 * 3 / 4;

fn main() {
    let x = add_one(MY_COMPUTATION);
}

into this code:

#![feature(inline_const)]

fn add_one(x: i32) -> i32 { x + 1 }
fn main() {
    let x = add_one(const { 1 + 2 * 3 / 4 });
}

inline_const_pat

The tracking issue for this feature is: #76001

See also inline_const


This feature allows you to use inline constant expressions in pattern position:

#![allow(unused)]
#![feature(inline_const_pat)]

fn main() {
const fn one() -> i32 { 1 }

let some_int = 3;
match some_int {
    const { 1 + 2 } => println!("Matched 1 + 2"),
    const { one() } => println!("Matched const fn returning 1"),
    _ => println!("Didn't match anything :("),
}
}

intra-doc-pointers

The tracking issue for this feature is: #80896


Rustdoc does not currently allow disambiguating between *const and *mut, and raw pointers in intra-doc links are unstable until it does.

#![allow(unused)]
#![feature(intra_doc_pointers)]
fn main() {
//! [pointer::add]
}

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

#![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.

isa_attribute

The tracking issue for this feature is: #74727


lang_items

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:

#![feature(lang_items, box_syntax, start, libc, core_intrinsics, rustc_private)]
#![no_std]
use core::intrinsics;
use core::panic::PanicInfo;

extern crate libc;

struct Unique<T>(*mut T);

#[lang = "owned_box"]
pub struct Box<T>(Unique<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 = "box_free"]
unsafe fn box_free<T: ?Sized>(ptr: *mut T) {
    libc::free(ptr as *mut libc::c_void)
}

#[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_impl"] extern fn rust_begin_panic(info: &PanicInfo) -> ! { unsafe { intrinsics::abort() } }
#[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, panic and panic_bounds_check 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 box_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:

[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:

#![feature(lang_items, core_intrinsics, rustc_private)]
#![feature(start)]
#![no_std]
use core::intrinsics;
use core::panic::PanicInfo;

// 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() {
}

#[lang = "panic_impl"]
#[no_mangle]
pub extern fn rust_begin_panic(info: &PanicInfo) -> ! {
    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:

#![feature(lang_items, core_intrinsics, rustc_private)]
#![feature(start)]
#![no_std]
#![no_main]
use core::intrinsics;
use core::panic::PanicInfo;

// 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() {
}

#[lang = "panic_impl"]
#[no_mangle]
pub extern fn rust_begin_panic(info: &PanicInfo) -> ! {
    unsafe { intrinsics::abort() }
}

In many cases, you may need to manually link to the compiler_builtins crate when building a no_std binary. You may observe this via linker error messages such as "undefined reference to `__rust_probestack'".

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 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.

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_impl, the symbol name is rust_begin_panic.

Finally, a eh_catch_typeinfo static is needed for certain targets which implement Rust panics on top of C++ exceptions.

List of all language items

This is a list of all language items in Rust along with where they are located in the source code.

  • Primitives
    • i8: libcore/num/mod.rs
    • i16: libcore/num/mod.rs
    • i32: libcore/num/mod.rs
    • i64: libcore/num/mod.rs
    • i128: libcore/num/mod.rs
    • isize: libcore/num/mod.rs
    • u8: libcore/num/mod.rs
    • u16: libcore/num/mod.rs
    • u32: libcore/num/mod.rs
    • u64: libcore/num/mod.rs
    • u128: libcore/num/mod.rs
    • usize: libcore/num/mod.rs
    • f32: libstd/f32.rs
    • f64: libstd/f64.rs
    • char: libcore/char.rs
    • slice: liballoc/slice.rs
    • str: liballoc/str.rs
    • const_ptr: libcore/ptr.rs
    • mut_ptr: libcore/ptr.rs
    • unsafe_cell: libcore/cell.rs
  • Runtime
    • start: libstd/rt.rs
    • eh_personality: libpanic_unwind/emcc.rs (EMCC)
    • eh_personality: libpanic_unwind/gcc.rs (GNU)
    • eh_personality: libpanic_unwind/seh.rs (SEH)
    • eh_catch_typeinfo: libpanic_unwind/emcc.rs (EMCC)
    • panic: libcore/panicking.rs
    • panic_bounds_check: libcore/panicking.rs
    • panic_impl: libcore/panicking.rs
    • panic_impl: libstd/panicking.rs
  • Allocations
    • owned_box: liballoc/boxed.rs
    • exchange_malloc: liballoc/heap.rs
    • box_free: liballoc/heap.rs
  • Operands
    • not: libcore/ops/bit.rs
    • bitand: libcore/ops/bit.rs
    • bitor: libcore/ops/bit.rs
    • bitxor: libcore/ops/bit.rs
    • shl: libcore/ops/bit.rs
    • shr: libcore/ops/bit.rs
    • bitand_assign: libcore/ops/bit.rs
    • bitor_assign: libcore/ops/bit.rs
    • bitxor_assign: libcore/ops/bit.rs
    • shl_assign: libcore/ops/bit.rs
    • shr_assign: libcore/ops/bit.rs
    • deref: libcore/ops/deref.rs
    • deref_mut: libcore/ops/deref.rs
    • index: libcore/ops/index.rs
    • index_mut: libcore/ops/index.rs
    • add: libcore/ops/arith.rs
    • sub: libcore/ops/arith.rs
    • mul: libcore/ops/arith.rs
    • div: libcore/ops/arith.rs
    • rem: libcore/ops/arith.rs
    • neg: libcore/ops/arith.rs
    • add_assign: libcore/ops/arith.rs
    • sub_assign: libcore/ops/arith.rs
    • mul_assign: libcore/ops/arith.rs
    • div_assign: libcore/ops/arith.rs
    • rem_assign: libcore/ops/arith.rs
    • eq: libcore/cmp.rs
    • ord: libcore/cmp.rs
  • Functions
    • fn: libcore/ops/function.rs
    • fn_mut: libcore/ops/function.rs
    • fn_once: libcore/ops/function.rs
    • generator_state: libcore/ops/generator.rs
    • generator: libcore/ops/generator.rs
  • Other
    • coerce_unsized: libcore/ops/unsize.rs
    • drop: libcore/ops/drop.rs
    • drop_in_place: libcore/ptr.rs
    • clone: libcore/clone.rs
    • copy: libcore/marker.rs
    • send: libcore/marker.rs
    • sized: libcore/marker.rs
    • unsize: libcore/marker.rs
    • sync: libcore/marker.rs
    • phantom_data: libcore/marker.rs
    • discriminant_kind: libcore/marker.rs
    • freeze: libcore/marker.rs
    • debug_trait: libcore/fmt/mod.rs
    • non_zero: libcore/nonzero.rs
    • arc: liballoc/sync.rs
    • rc: liballoc/rc.rs

large_assignments

The tracking issue for this feature is: #83518


let_chains

The tracking issue for this feature is: #53667


let_else

The tracking issue for this feature is: #87335


link_cfg

This feature is internal to the Rust compiler and is not intended for general use.


link_llvm_intrinsics

The tracking issue for this feature is: #29602


linkage

The tracking issue for this feature is: #29603


lint_reasons

The tracking issue for this feature is: #54503


macro_metavar_expr

The tracking issue for this feature is: #83527


marker_trait_attr

The tracking issue for this feature is: #29864


Normally, Rust keeps you from adding trait implementations that could overlap with each other, as it would be ambiguous which to use. This feature, however, carves out an exception to that rule: a trait can opt-in to having overlapping implementations, at the cost that those implementations are not allowed to override anything (and thus the trait itself cannot have any associated items, as they're pointless when they'd need to do the same thing for every type anyway).

#![allow(unused)]
#![feature(marker_trait_attr)]

fn main() {
#[marker] trait CheapToClone: Clone {}

impl<T: Copy> CheapToClone for T {}

// These could potentially overlap with the blanket implementation above,
// so are only allowed because CheapToClone is a marker trait.
impl<T: CheapToClone, U: CheapToClone> CheapToClone for (T, U) {}
impl<T: CheapToClone> CheapToClone for std::ops::Range<T> {}

fn cheap_clone<T: CheapToClone>(t: T) -> T {
    t.clone()
}
}

This is expected to replace the unstable overlapping_marker_traits feature, which applied to all empty traits (without needing an opt-in).

min_specialization

The tracking issue for this feature is: #31844


mips_target_feature

The tracking issue for this feature is: #44839


more_qualified_paths

The more_qualified_paths feature can be used in order to enable the use of qualified paths in patterns.

Example

#![feature(more_qualified_paths)]

fn main() {
    // destructure through a qualified path
    let <Foo as A>::Assoc { br } = StructStruct { br: 2 };
}

struct StructStruct {
    br: i8,
}

struct Foo;

trait A {
    type Assoc;
}

impl A for Foo {
    type Assoc = StructStruct;
}

movbe_target_feature

The tracking issue for this feature is: #44839


must_not_suspend

The tracking issue for this feature is: #83310


naked_functions

The tracking issue for this feature is: #32408


native_link_modifiers_as_needed

The tracking issue for this feature is: #81490


The native_link_modifiers_as_needed feature allows you to use the as-needed modifier.

as-needed is only compatible with the dynamic and framework linking kinds. Using any other kind will result in a compiler error.

+as-needed means that the library will be actually linked only if it satisfies some undefined symbols at the point at which it is specified on the command line, making it similar to static libraries in this regard.

This modifier translates to --as-needed for ld-like linkers, and to -dead_strip_dylibs / -needed_library / -needed_framework for ld64. The modifier does nothing for linkers that don't support it (e.g. link.exe).

The default for this modifier is unclear, some targets currently specify it as +as-needed, some do not. We may want to try making +as-needed a default for all targets.

native_link_modifiers_verbatim

The tracking issue for this feature is: #81490


The native_link_modifiers_verbatim feature allows you to use the verbatim modifier.

+verbatim means that rustc itself won't add any target-specified library prefixes or suffixes (like lib or .a) to the library name, and will try its best to ask for the same thing from the linker.

For ld-like linkers rustc will use the -l:filename syntax (note the colon) when passing the library, so the linker won't add any prefixes or suffixes as well. See -l namespec in ld documentation for more details. For linkers not supporting any verbatim modifiers (e.g. link.exe or ld64) the library name will be passed as is.

The default for this modifier is -verbatim.

This RFC changes the behavior of raw-dylib linking kind specified by RFC 2627. The .dll suffix (or other target-specified suffixes for other targets) is now added automatically. If your DLL doesn't have the .dll suffix, it can be specified with +verbatim.

needs_panic_runtime

The tracking issue for this feature is: #32837


negative_impls

The tracking issue for this feature is #68318.


With the feature gate negative_impls, you can write negative impls as well as positive ones:

#![allow(unused)]
#![feature(negative_impls)]
fn main() {
trait DerefMut { }
impl<T: ?Sized> !DerefMut for &T { }
}

Negative impls indicate a semver guarantee that the given trait will not be implemented for the given types. Negative impls play an additional purpose for auto traits, described below.

Negative impls have the following characteristics:

  • They do not have any items.
  • They must obey the orphan rules as if they were a positive impl.
  • They cannot "overlap" with any positive impls.

Semver interaction

It is a breaking change to remove a negative impl. Negative impls are a commitment not to implement the given trait for the named types.

Orphan and overlap rules

Negative impls must obey the same orphan rules as a positive impl. This implies you cannot add a negative impl for types defined in upstream crates and so forth.

Similarly, negative impls cannot overlap with positive impls, again using the same "overlap" check that we ordinarily use to determine if two impls overlap. (Note that positive impls typically cannot overlap with one another either, except as permitted by specialization.)

Interaction with auto traits

Declaring a negative impl impl !SomeAutoTrait for SomeType for an auto-trait serves two purposes:

  • as with any trait, it declares that SomeType will never implement SomeAutoTrait;
  • it disables the automatic SomeType: SomeAutoTrait impl that would otherwise have been generated.

Note that, at present, there is no way to indicate that a given type does not implement an auto trait but that it may do so in the future. For ordinary types, this is done by simply not declaring any impl at all, but that is not an option for auto traits. A workaround is that one could embed a marker type as one of the fields, where the marker type is !AutoTrait.

Immediate uses

Negative impls are used to declare that &T: !DerefMut and &mut T: !Clone, as required to fix the soundness of Pin described in #66544.

This serves two purposes:

  • For proving the correctness of unsafe code, we can use that impl as evidence that no DerefMut or Clone impl exists.
  • It prevents downstream crates from creating such impls.

never_type

The tracking issue for this feature is: #35121


never_type_fallback

The tracking issue for this feature is: #65992


no_core

The tracking issue for this feature is: #29639


no_coverage

The tracking issue for this feature is: #84605


The no_coverage attribute can be used to selectively disable coverage instrumentation in an annotated function. This might be useful to:

  • Avoid instrumentation overhead in a performance critical function
  • Avoid generating coverage for a function that is not meant to be executed, but still target 100% coverage for the rest of the program.

Example

#![allow(unused)]
#![feature(no_coverage)]

fn main() {
// `foo()` will get coverage instrumentation (by default)
fn foo() {
  // ...
}

#[no_coverage]
fn bar() {
  // ...
}
}

no_sanitize

The tracking issue for this feature is: #39699


The no_sanitize attribute can be used to selectively disable sanitizer instrumentation in an annotated function. This might be useful to: avoid instrumentation overhead in a performance critical function, or avoid instrumenting code that contains constructs unsupported by given sanitizer.

The precise effect of this annotation depends on particular sanitizer in use. For example, with no_sanitize(thread), the thread sanitizer will no longer instrument non-atomic store / load operations, but it will instrument atomic operations to avoid reporting false positives and provide meaning full stack traces.

Examples

#![allow(unused)]
#![feature(no_sanitize)]

fn main() {
#[no_sanitize(address)]
fn foo() {
  // ...
}
}

non_exhaustive_omitted_patterns_lint

The tracking issue for this feature is: #89554


object_safe_for_dispatch

The tracking issue for this feature is: #43561


omit_gdb_pretty_printer_section

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


optimize_attribute

The tracking issue for this feature is: #54882


panic_runtime

The tracking issue for this feature is: #32837


platform_intrinsics

The tracking issue for this feature is: #27731


plugin

The tracking issue for this feature is: #29597

This feature is part of "compiler plugins." It will often be used with the rustc_private feature.


rustc can load compiler plugins, which are user-provided libraries that extend the compiler's behavior with new 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_driver::plugin documentation for more about the mechanics of defining and loading a plugin.

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 librustc_ast and librustc as dependencies of your crate. This is generally unwanted unless you are building another plugin.

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.

Lint plugins

Plugins can extend Rust's lint infrastructure with additional checks for code style, safety, etc. Now let's write a plugin lint-plugin-test.rs that warns about any item named lintme.

#![feature(box_syntax, rustc_private)]

extern crate rustc_ast;

// Load rustc as a plugin to get macros
extern crate rustc_driver;
#[macro_use]
extern crate rustc_lint;
#[macro_use]
extern crate rustc_session;

use rustc_driver::plugin::Registry;
use rustc_lint::{EarlyContext, EarlyLintPass, LintArray, LintContext, LintPass};
use rustc_ast::ast;
declare_lint!(TEST_LINT, Warn, "Warn about items named 'lintme'");

declare_lint_pass!(Pass => [TEST_LINT]);

impl EarlyLintPass for Pass {
    fn check_item(&mut self, cx: &EarlyContext, it: &ast::Item) {
        if it.ident.name.as_str() == "lintme" {
            cx.lint(TEST_LINT, |lint| {
                lint.build("item is named 'lintme'").set_span(it.span).emit()
            });
        }
    }
}

#[no_mangle]
fn __rustc_plugin_registrar(reg: &mut Registry) {
    reg.lint_store.register_lints(&[&TEST_LINT]);
    reg.lint_store.register_early_pass(|| box Pass);
}

Then code like

#![feature(plugin)]
#![plugin(lint_plugin_test)]

fn lintme() { }

will produce a compiler warning:

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 Lints, 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 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, 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.

powerpc_target_feature

The tracking issue for this feature is: #44839


precise_pointer_size_matching

The tracking issue for this feature is: #56354


prelude_import

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


proc_macro_hygiene

The tracking issue for this feature is: #54727


profiler_runtime

The tracking issue for this feature is: #42524.


raw_dylib

The tracking issue for this feature is: #58713


The raw_dylib feature allows you to link against the implementations of functions in an extern block without, on Windows, linking against an import library.

#![feature(raw_dylib)]

#[link(name="library", kind="raw-dylib")]
extern {
    fn extern_function(x: i32);
}

fn main() {
    unsafe {
        extern_function(14);
    }
}

Limitations

This feature is unstable for the x86 architecture, and stable for all other architectures.

This feature is only supported on Windows.

On the x86 architecture, this feature supports only the cdecl, stdcall, system, fastcall, and vectorcall calling conventions.

raw_ref_op

The tracking issue for this feature is: #64490


register_tool

The tracking issue for this feature is: #66079


repr_simd

The tracking issue for this feature is: #27731


repr128

The tracking issue for this feature is: #56071


The repr128 feature adds support for #[repr(u128)] on enums.

#![allow(unused)]
#![feature(repr128)]

fn main() {
#[repr(u128)]
enum Foo {
    Bar(u64),
}
}

return_position_impl_trait_in_trait

The tracking issue for this feature is: #91611


riscv_target_feature

The tracking issue for this feature is: #44839


rtm_target_feature

The tracking issue for this feature is: #44839


rust_cold_cc

The tracking issue for this feature is: #97544


rustc_allow_const_fn_unstable

The tracking issue for this feature is: #69399


rustc_attrs

This feature has no tracking issue, and is therefore internal to the compiler, not being intended for general use.

Note: rustc_attrs enables many rustc-internal attributes and this page only discuss a few of them.


The rustc_attrs feature allows debugging rustc type layouts by using #[rustc_layout(...)] to debug layout at compile time (it even works with cargo check) as an alternative to rustc -Z print-type-sizes that is way more verbose.

Options provided by #[rustc_layout(...)] are debug, size, align, abi. Note that it only works on sized types without generics.

Examples

#![allow(unused)]
#![feature(rustc_attrs)]

fn main() {
#[rustc_layout(abi, size)]
pub enum X {
    Y(u8, u8, u8),
    Z(isize),
}
}

When that is compiled, the compiler will error with something like

error: abi: Aggregate { sized: true }
 --> src/lib.rs:4:1
  |
4 | / pub enum T {
5 | |     Y(u8, u8, u8),
6 | |     Z(isize),
7 | | }
  | |_^

error: size: Size { raw: 16 }
 --> src/lib.rs:4:1
  |
4 | / pub enum T {
5 | |     Y(u8, u8, u8),
6 | |     Z(isize),
7 | | }
  | |_^

error: aborting due to 2 previous errors

rustc_private

The tracking issue for this feature is: #27812


rustdoc_internals

The tracking issue for this feature is: #90418


rustdoc_missing_doc_code_examples

The tracking issue for this feature is: #101730


simd_ffi

The tracking issue for this feature is: #27731


specialization

The tracking issue for this feature is: #31844


sse4a_target_feature

The tracking issue for this feature is: #44839


staged_api

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


start

The tracking issue for this feature is: #29633


stmt_expr_attributes

The tracking issue for this feature is: #15701


strict_provenance

The tracking issue for this feature is: #95228


The strict_provenance feature allows to enable the fuzzy_provenance_casts and lossy_provenance_casts lints. These lint on casts between integers and pointers, that are recommended against or invalid in the strict provenance model. The same feature gate is also used for the experimental strict provenance API in std (actually core).

Example

#![feature(strict_provenance)]
#![warn(fuzzy_provenance_casts)]

fn main() {
    let _dangling = 16_usize as *const u8;
    //~^ WARNING: strict provenance disallows casting integer `usize` to pointer `*const u8`
}

structural_match

The tracking issue for this feature is: #31434


target_feature_11

The tracking issue for this feature is: #69098


tbm_target_feature

The tracking issue for this feature is: #44839


test_2018_feature

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


test_unstable_lint

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


thread_local

The tracking issue for this feature is: #29594


trait_alias

The tracking issue for this feature is: #41517


The trait_alias feature adds support for trait aliases. These allow aliases to be created for one or more traits (currently just a single regular trait plus any number of auto-traits), and used wherever traits would normally be used as either bounds or trait objects.

#![feature(trait_alias)]

trait Foo = std::fmt::Debug + Send;
trait Bar = Foo + Sync;

// Use trait alias as bound on type parameter.
fn foo<T: Foo>(v: &T) {
    println!("{:?}", v);
}

pub fn main() {
    foo(&1);

    // Use trait alias for trait objects.
    let a: &Bar = &123;
    println!("{:?}", a);
    let b = Box::new(456) as Box<dyn Foo>;
    println!("{:?}", b);
}

trait_upcasting

The tracking issue for this feature is: #65991


The trait_upcasting feature adds support for trait upcasting coercion. This allows a trait object of type dyn Bar to be cast to a trait object of type dyn Foo so long as Bar: Foo.

#![allow(unused)]
#![feature(trait_upcasting)]
#![allow(incomplete_features)]

fn main() {
trait Foo {}

trait Bar: Foo {}

impl Foo for i32 {}

impl<T: Foo + ?Sized> Bar for T {}

let bar: &dyn Bar = &123;
let foo: &dyn Foo = bar;
}

transparent_unions

The tracking issue for this feature is #60405


The transparent_unions feature allows you mark unions as #[repr(transparent)]. A union may be #[repr(transparent)] in exactly the same conditions in which a struct may be #[repr(transparent)] (generally, this means the union must have exactly one non-zero-sized field). Some concrete illustrations follow.

#![allow(unused)]
#![feature(transparent_unions)]

fn main() {
// This union has the same representation as `f32`.
#[repr(transparent)]
union SingleFieldUnion {
    field: f32,
}

// This union has the same representation as `usize`.
#[repr(transparent)]
union MultiFieldUnion {
    field: usize,
    nothing: (),
}
}

For consistency with transparent structs, unions must have exactly one non-zero-sized field. If all fields are zero-sized, the union must not be #[repr(transparent)]:

#![allow(unused)]
#![feature(transparent_unions)]

fn main() {
// This (non-transparent) union is already valid in stable Rust:
pub union GoodUnion {
    pub nothing: (),
}

// Error: transparent union needs exactly one non-zero-sized field, but has 0
// #[repr(transparent)]
// pub union BadUnion {
//     pub nothing: (),
// }
}

The one exception is if the union is generic over T and has a field of type T, it may be #[repr(transparent)] even if T is a zero-sized type:

#![allow(unused)]
#![feature(transparent_unions)]

fn main() {
// This union has the same representation as `T`.
#[repr(transparent)]
pub union GenericUnion<T: Copy> { // Unions with non-`Copy` fields are unstable.
    pub field: T,
    pub nothing: (),
}

// This is okay even though `()` is a zero-sized type.
pub const THIS_IS_OKAY: GenericUnion<()> = GenericUnion { field: () };
}

Like transarent structs, a transparent union of type U has the same layout, size, and ABI as its single non-ZST field. If it is generic over a type T, and all its fields are ZSTs except for exactly one field of type T, then it has the same layout and ABI as T (even if T is a ZST when monomorphized).

Like transparent structs, transparent unions are FFI-safe if and only if their underlying representation type is also FFI-safe.

A union may not be eligible for the same nonnull-style optimizations that a struct or enum (with the same fields) are eligible for. Adding #[repr(transparent)] to union does not change this. To give a more concrete example, it is unspecified whether size_of::<T>() is equal to size_of::<Option<T>>(), where T is a union (regardless of whether or not it is transparent). The Rust compiler is free to perform this optimization if possible, but is not required to, and different compiler versions may differ in their application of these optimizations.

trivial_bounds

The tracking issue for this feature is: #48214


try_blocks

The tracking issue for this feature is: #31436


The try_blocks feature adds support for try blocks. A try block creates a new scope one can use the ? operator in.

#![allow(unused)]
#![feature(try_blocks)]

fn main() {
use std::num::ParseIntError;

let result: Result<i32, ParseIntError> = try {
    "1".parse::<i32>()?
        + "2".parse::<i32>()?
        + "3".parse::<i32>()?
};
assert_eq!(result, Ok(6));

let result: Result<i32, ParseIntError> = try {
    "1".parse::<i32>()?
        + "foo".parse::<i32>()?
        + "3".parse::<i32>()?
};
assert!(result.is_err());
}

type_alias_impl_trait

The tracking issue for this feature is: #63063


type_ascription

The tracking issue for this feature is: #23416


type_changing_struct_update

The tracking issue for this feature is: #86555


This implements RFC2528. When turned on, you can create instances of the same struct that have different generic type or lifetime parameters.

#![allow(unused_variables, dead_code)]
#![feature(type_changing_struct_update)]

fn main () {
    struct Foo<T, U> {
        field1: T,
        field2: U,
    }

    let base: Foo<String, i32> = Foo {
        field1: String::from("hello"),
        field2: 1234,
    };
    let updated: Foo<f64, i32> = Foo {
        field1: 3.14,
        ..base
    };
}

unboxed_closures

The tracking issue for this feature is #29625

See Also: fn_traits


The unboxed_closures feature allows you to write functions using the "rust-call" ABI, required for implementing the Fn* family of traits. "rust-call" functions must have exactly one (non self) argument, a tuple representing the argument list.

#![feature(unboxed_closures)]

extern "rust-call" fn add_args(args: (u32, u32)) -> u32 {
    args.0 + args.1
}

fn main() {}

unix_sigpipe

The tracking issue for this feature is: #97889


The #[unix_sigpipe = "..."] attribute on fn main() can be used to specify how libstd shall setup SIGPIPE on Unix platforms before invoking fn main(). This attribute is ignored on non-Unix targets. There are three variants:

  • #[unix_sigpipe = "inherit"]
  • #[unix_sigpipe = "sig_dfl"]
  • #[unix_sigpipe = "sig_ign"]

#[unix_sigpipe = "inherit"]

Leave SIGPIPE untouched before entering fn main(). Unless the parent process has changed the default SIGPIPE handler from SIG_DFL to something else, this will behave the same as #[unix_sigpipe = "sig_dfl"].

#[unix_sigpipe = "sig_dfl"]

Set the SIGPIPE handler to SIG_DFL. This will result in your program getting killed if it tries to write to a closed pipe. This is normally what you want if your program produces textual output.

Example

#![feature(unix_sigpipe)]
#[unix_sigpipe = "sig_dfl"]
fn main() { loop { println!("hello world"); } }
% ./main | head -n 1
hello world

#[unix_sigpipe = "sig_ign"]

Set the SIGPIPE handler to SIG_IGN before invoking fn main(). This will result in ErrorKind::BrokenPipe errors if you program tries to write to a closed pipe. This is normally what you want if you for example write socket servers, socket clients, or pipe peers.

This is what libstd has done by default since 2014. Omitting #[unix_sigpipe = "..."] is the same as having #[unix_sigpipe = "sig_ign"].

Example

#![feature(unix_sigpipe)]
#[unix_sigpipe = "sig_ign"]
fn main() { loop { println!("hello world"); } }
% ./main | head -n 1
hello world
thread 'main' panicked at 'failed printing to stdout: Broken pipe (os error 32)', library/std/src/io/stdio.rs:1016:9
note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace

unsafe_pin_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


unsized_fn_params

The tracking issue for this feature is: #48055


unsized_locals

The tracking issue for this feature is: #48055


This implements RFC1909. When turned on, you can have unsized arguments and locals:

#![allow(incomplete_features)]
#![feature(unsized_locals, unsized_fn_params)]

use std::any::Any;

fn main() {
    let x: Box<dyn Any> = Box::new(42);
    let x: dyn Any = *x;
    //  ^ unsized local variable
    //               ^^ unsized temporary
    foo(x);
}

fn foo(_: dyn Any) {}
//     ^^^^^^ unsized argument

The RFC still forbids the following unsized expressions:

#![feature(unsized_locals)]

use std::any::Any;

struct MyStruct<T: ?Sized> {
    content: T,
}

struct MyTupleStruct<T: ?Sized>(T);

fn answer() -> Box<dyn Any> {
    Box::new(42)
}

fn main() {
    // You CANNOT have unsized statics.
    static X: dyn Any = *answer();  // ERROR
    const Y: dyn Any = *answer();  // ERROR

    // You CANNOT have struct initialized unsized.
    MyStruct { content: *answer() };  // ERROR
    MyTupleStruct(*answer());  // ERROR
    (42, *answer());  // ERROR

    // You CANNOT have unsized return types.
    fn my_function() -> dyn Any { *answer() }  // ERROR

    // You CAN have unsized local variables...
    let mut x: dyn Any = *answer();  // OK
    // ...but you CANNOT reassign to them.
    x = *answer();  // ERROR

    // You CANNOT even initialize them separately.
    let y: dyn Any;  // OK
    y = *answer();  // ERROR

    // Not mentioned in the RFC, but by-move captured variables are also Sized.
    let x: dyn Any = *answer();
    (move || {  // ERROR
        let y = x;
    })();

    // You CAN create a closure with unsized arguments,
    // but you CANNOT call it.
    // This is an implementation detail and may be changed in the future.
    let f = |x: dyn Any| {};
    f(*answer());  // ERROR
}

By-value trait objects

With this feature, you can have by-value self arguments without Self: Sized bounds.

#![feature(unsized_fn_params)]

trait Foo {
    fn foo(self) {}
}

impl<T: ?Sized> Foo for T {}

fn main() {
    let slice: Box<[i32]> = Box::new([1, 2, 3]);
    <[i32] as Foo>::foo(*slice);
}

And Foo will also be object-safe.

#![feature(unsized_fn_params)]

trait Foo {
    fn foo(self) {}
}

impl<T: ?Sized> Foo for T {}

fn main () {
    let slice: Box<dyn Foo> = Box::new([1, 2, 3]);
    // doesn't compile yet
    <dyn Foo as Foo>::foo(*slice);
}

One of the objectives of this feature is to allow Box<dyn FnOnce>.

Variable length arrays

The RFC also describes an extension to the array literal syntax: [e; dyn n]. In the syntax, n isn't necessarily a constant expression. The array is dynamically allocated on the stack and has the type of [T], instead of [T; n].

#![feature(unsized_locals)]

fn mergesort<T: Ord>(a: &mut [T]) {
    let mut tmp = [T; dyn a.len()];
    // ...
}

fn main() {
    let mut a = [3, 1, 5, 6];
    mergesort(&mut a);
    assert_eq!(a, [1, 3, 5, 6]);
}

VLAs are not implemented yet. The syntax isn't final, either. We may need an alternative syntax for Rust 2015 because, in Rust 2015, expressions like [e; dyn(1)] would be ambiguous. One possible alternative proposed in the RFC is [e; n]: if n captures one or more local variables, then it is considered as [e; dyn n].

Advisory on stack usage

It's advised not to casually use the #![feature(unsized_locals)] feature. Typical use-cases are:

  • When you need a by-value trait objects.
  • When you really need a fast allocation of small temporary arrays.

Another pitfall is repetitive allocation and temporaries. Currently the compiler simply extends the stack frame every time it encounters an unsized assignment. So for example, the code

#![feature(unsized_locals)]

fn main() {
    let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
    let _x = {{{{{{{{{{*x}}}}}}}}}};
}

and the code

#![feature(unsized_locals)]

fn main() {
    for _ in 0..10 {
        let x: Box<[i32]> = Box::new([1, 2, 3, 4, 5]);
        let _x = *x;
    }
}

will unnecessarily extend the stack frame.

unsized_tuple_coercion

The tracking issue for this feature is: #42877


This is a part of RFC0401. According to the RFC, there should be an implementation like this:

impl<..., T, U: ?Sized> Unsized<(..., U)> for (..., T) where T: Unsized<U> {}

This implementation is currently gated behind #[feature(unsized_tuple_coercion)] to avoid insta-stability. Therefore you can use it like this:

#![feature(unsized_tuple_coercion)]

fn main() {
    let x : ([i32; 3], [i32; 3]) = ([1, 2, 3], [4, 5, 6]);
    let y : &([i32; 3], [i32]) = &x;
    assert_eq!(y.1[0], 4);
}

used_with_arg

The tracking issue for this feature is: #93798


wasm_abi

The tracking issue for this feature is: #83788


wasm_target_feature

The tracking issue for this feature is: #44839


with_negative_coherence

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


yeet_expr

The tracking issue for this feature is: #96373


The yeet_expr feature adds support for do yeet expressions, which can be used to early-exit from a function or try block.

These are highly experimental, thus the placeholder syntax.

#![allow(unused)]
#![feature(yeet_expr)]

fn main() {
fn foo() -> Result<String, i32> {
    do yeet 4;
}
assert_eq!(foo(), Err(4));

fn bar() -> Option<String> {
    do yeet;
}
assert_eq!(bar(), None);
}

Library Features

absolute_path

The tracking issue for this feature is: #92750


addr_parse_ascii

The tracking issue for this feature is: #101035


alloc_error_hook

The tracking issue for this feature is: #51245


alloc_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


alloc_layout_extra

The tracking issue for this feature is: #55724


allocator_api

The tracking issue for this feature is #32838


Sometimes you want the memory for one collection to use a different allocator than the memory for another collection. In this case, replacing the global allocator is not a workable option. Instead, you need to pass in an instance of an AllocRef to each collection for which you want a custom allocator.

TBD

arc_unwrap_or_clone

The tracking issue for this feature is: #93610


array_chunks

The tracking issue for this feature is: #74985


array_error_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


array_into_iter_constructors

The tracking issue for this feature is: #91583


array_methods

The tracking issue for this feature is: #76118


array_try_from_fn

The tracking issue for this feature is: #89379


array_try_map

The tracking issue for this feature is: #79711


array_windows

The tracking issue for this feature is: #75027


array_zip

The tracking issue for this feature is: #80094


as_array_of_cells

The tracking issue for this feature is: #88248


assert_matches

The tracking issue for this feature is: #82775


async_iter_from_iter

The tracking issue for this feature is: #81798


async_iterator

The tracking issue for this feature is: #79024


atomic_bool_fetch_not

The tracking issue for this feature is: #98485


atomic_from_mut

The tracking issue for this feature is: #76314


atomic_mut_ptr

The tracking issue for this feature is: #66893


backtrace_frames

The tracking issue for this feature is: #79676


bench_black_box

The tracking issue for this feature is: #64102


bigint_helper_methods

The tracking issue for this feature is: #85532


binary_heap_as_slice

The tracking issue for this feature is: #83659


binary_heap_drain_sorted

The tracking issue for this feature is: #59278


binary_heap_into_iter_sorted

The tracking issue for this feature is: #59278


binary_heap_retain

The tracking issue for this feature is: #71503


bound_as_ref

The tracking issue for this feature is: #80996


bound_map

The tracking issue for this feature is: #86026


box_into_boxed_slice

The tracking issue for this feature is: #71582


box_into_inner

The tracking issue for this feature is: #80437


btree_drain_filter

The tracking issue for this feature is: #70530


btreemap_alloc

The tracking issue for this feature is: #32838


buf_read_has_data_left

The tracking issue for this feature is: #86423


build_hasher_simple_hash_one

The tracking issue for this feature is: #86161


byte_slice_trim_ascii

The tracking issue for this feature is: #94035


c_size_t

The tracking issue for this feature is: #88345


c_void_variant

This feature is internal to the Rust compiler and is not intended for general use.


can_vector

The tracking issue for this feature is: #69941


cell_leak

The tracking issue for this feature is: #69099


cell_update

The tracking issue for this feature is: #50186


cfg_accessible

The tracking issue for this feature is: #64797


cfg_eval

The tracking issue for this feature is: #82679


char_error_internals

This feature is internal to the Rust compiler and is not intended for general use.


char_indices_offset

The tracking issue for this feature is: #83871


char_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


coerce_unsized

The tracking issue for this feature is: #27732


concat_bytes

The tracking issue for this feature is: #87555


concat_idents

The tracking issue for this feature is: #29599


The concat_idents feature adds a macro for concatenating multiple identifiers into one identifier.

Examples

#![feature(concat_idents)]

fn main() {
    fn foobar() -> u32 { 23 }
    let f = concat_idents!(foo, bar);
    assert_eq!(f(), 23);
}

const_align_of_val

The tracking issue for this feature is: #46571


const_align_of_val_raw

The tracking issue for this feature is: #46571


const_align_offset

The tracking issue for this feature is: #90962


const_alloc_error

The tracking issue for this feature is: #92523


const_alloc_layout

The tracking issue for this feature is: #67521


const_arguments_as_str

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_array_from_ref

The tracking issue for this feature is: #90206


const_array_into_iter_constructors

The tracking issue for this feature is: #91583


const_assert_type2

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_assume

The tracking issue for this feature is: #76972


const_bigint_helper_methods

The tracking issue for this feature is: #85532


const_black_box

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_bool_to_option

The tracking issue for this feature is: #91917


const_borrow

The tracking issue for this feature is: #91522


const_box

The tracking issue for this feature is: #92521


const_btree_new

The tracking issue for this feature is: #71835


const_caller_location

The tracking issue for this feature is: #76156


const_cell_into_inner

The tracking issue for this feature is: #78729


const_char_convert

The tracking issue for this feature is: #89259


const_clone

The tracking issue for this feature is: #91805


const_cmp

The tracking issue for this feature is: #92391


const_convert

The tracking issue for this feature is: #88674


const_cow_is_borrowed

The tracking issue for this feature is: #65143


const_cstr_methods

The tracking issue for this feature is: #101719


const_default_impls

The tracking issue for this feature is: #87864


const_deref

The tracking issue for this feature is: #88955


const_discriminant

The tracking issue for this feature is: #69821


const_eval_select

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_float_bits_conv

The tracking issue for this feature is: #72447


const_float_classify

The tracking issue for this feature is: #72505


const_fmt_arguments_new

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_format_args

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_heap

The tracking issue for this feature is: #79597


const_inherent_unchecked_arith

The tracking issue for this feature is: #85122


const_int_unchecked_arith

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_intoiterator_identity

The tracking issue for this feature is: #90603


const_intrinsic_forget

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_intrinsic_raw_eq

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_io_structs

The tracking issue for this feature is: #78812


const_ip

The tracking issue for this feature is: #76205


const_ipv4

The tracking issue for this feature is: #76205


const_ipv6

The tracking issue for this feature is: #76205


const_is_char_boundary

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_likely

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_maybe_uninit_array_assume_init

The tracking issue for this feature is: #96097


const_maybe_uninit_as_mut_ptr

The tracking issue for this feature is: #75251


const_maybe_uninit_assume_init

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_maybe_uninit_assume_init_read

The tracking issue for this feature is: #63567


const_maybe_uninit_uninit_array

The tracking issue for this feature is: #96097


const_maybe_uninit_write

The tracking issue for this feature is: #63567


const_maybe_uninit_zeroed

The tracking issue for this feature is: #91850


const_nonnull_new

The tracking issue for this feature is: #93235


const_nonnull_slice_from_raw_parts

The tracking issue for this feature is: #71941


const_num_from_num

The tracking issue for this feature is: #87852


const_ops

The tracking issue for this feature is: #90080


const_option

The tracking issue for this feature is: #67441


const_option_cloned

The tracking issue for this feature is: #91582


const_option_ext

The tracking issue for this feature is: #91930


const_pin

The tracking issue for this feature is: #76654


const_pointer_byte_offsets

The tracking issue for this feature is: #96283


const_pref_align_of

The tracking issue for this feature is: #91971


const_ptr_as_ref

The tracking issue for this feature is: #91822


const_ptr_is_null

The tracking issue for this feature is: #74939


const_ptr_read

The tracking issue for this feature is: #80377


const_ptr_sub_ptr

The tracking issue for this feature is: #95892


const_ptr_write

The tracking issue for this feature is: #86302


const_raw_ptr_comparison

The tracking issue for this feature is: #53020


const_replace

The tracking issue for this feature is: #83164


const_result

The tracking issue for this feature is: #82814


const_result_drop

The tracking issue for this feature is: #92384


const_reverse

The tracking issue for this feature is: #100784


const_size_of_val

The tracking issue for this feature is: #46571


const_size_of_val_raw

The tracking issue for this feature is: #46571


const_slice_first_last

The tracking issue for this feature is: #83570


const_slice_from_mut_ptr_range

The tracking issue for this feature is: #89792


const_slice_from_ptr_range

The tracking issue for this feature is: #89792


const_slice_from_raw_parts_mut

The tracking issue for this feature is: #67456


const_slice_from_ref

The tracking issue for this feature is: #90206


const_slice_index

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


const_slice_ptr_len

The tracking issue for this feature is: #71146


const_slice_split_at_not_mut

The tracking issue for this feature is: #101158


const_socketaddr

The tracking issue for this feature is: #82485


const_str_from_utf8

The tracking issue for this feature is: #91006


const_str_from_utf8_unchecked_mut

The tracking issue for this feature is: #91005


const_swap

The tracking issue for this feature is: #83163


const_transmute_copy

The tracking issue for this feature is: #83165


const_type_id

The tracking issue for this feature is: #77125


const_type_name

The tracking issue for this feature is: #63084


const_unicode_case_lookup

The tracking issue for this feature is: #101400


const_unsafecell_get_mut

The tracking issue for this feature is: #88836


const_weak_new

The tracking issue for this feature is: #95091


container_error_extra

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


control_flow_enum

The tracking issue for this feature is: #75744


convert_float_to_int

The tracking issue for this feature is: #67057


core_intrinsics

This feature is internal to the Rust compiler and is not intended for general use.


core_panic

This feature is internal to the Rust compiler and is not intended for general use.


core_private_bignum

This feature is internal to the Rust compiler and is not intended for general use.


core_private_diy_float

This feature is internal to the Rust compiler and is not intended for general use.


cow_is_borrowed

The tracking issue for this feature is: #65143


cstr_from_bytes_until_nul

The tracking issue for this feature is: #95027


cstr_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


cursor_remaining

The tracking issue for this feature is: #86369


deadline_api

The tracking issue for this feature is: #46316


dec2flt

This feature is internal to the Rust compiler and is not intended for general use.


default_free_fn

The tracking issue for this feature is: #73014


Adds a free default() function to the std::default module. This function just forwards to Default::default(), but may remove repetition of the word "default" from the call site.

Here is an example:

#![feature(default_free_fn)]
use std::default::default;

#[derive(Default)]
struct AppConfig {
    foo: FooConfig,
    bar: BarConfig,
}

#[derive(Default)]
struct FooConfig {
    foo: i32,
}

#[derive(Default)]
struct BarConfig {
    bar: f32,
    baz: u8,
}

fn main() {
    let options = AppConfig {
        foo: default(),
        bar: BarConfig {
            bar: 10.1,
            ..default()
        },
    };
}

derive_clone_copy

This feature is internal to the Rust compiler and is not intended for general use.


derive_eq

This feature is internal to the Rust compiler and is not intended for general use.


dir_entry_ext2

The tracking issue for this feature is: #85573


discriminant_kind

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


dispatch_from_dyn

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


div_duration

The tracking issue for this feature is: #63139


downcast_unchecked

The tracking issue for this feature is: #90850


drain_filter

The tracking issue for this feature is: #43244


drain_keep_rest

The tracking issue for this feature is: #101122


duration_checked_float

The tracking issue for this feature is: #83400


duration_constants

The tracking issue for this feature is: #57391


duration_consts_float

The tracking issue for this feature is: #72440


edition_panic

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


entry_insert

The tracking issue for this feature is: #65225


error_generic_member_access

The tracking issue for this feature is: #99301


error_in_core

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


error_iter

The tracking issue for this feature is: #58520


error_reporter

The tracking issue for this feature is: #90172


error_type_id

The tracking issue for this feature is: #60784


exact_size_is_empty

The tracking issue for this feature is: #35428


exclusive_wrapper

The tracking issue for this feature is: #98407


exit_status_error

The tracking issue for this feature is: #84908


exitcode_exit_method

The tracking issue for this feature is: #97100


extend_one

The tracking issue for this feature is: #72631


fd

This feature is internal to the Rust compiler and is not intended for general use.


fd_read

This feature is internal to the Rust compiler and is not intended for general use.


file_create_new

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


file_set_times

The tracking issue for this feature is: #98245


float_minimum_maximum

The tracking issue for this feature is: #91079


float_next_up_down

The tracking issue for this feature is: #91399


flt2dec

This feature is internal to the Rust compiler and is not intended for general use.


fmt_helpers_for_derive

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


fmt_internals

This feature is internal to the Rust compiler and is not intended for general use.


fn_traits

The tracking issue for this feature is #29625

See Also: unboxed_closures


The fn_traits feature allows for implementation of the Fn* traits for creating custom closure-like types.

#![feature(unboxed_closures)]
#![feature(fn_traits)]

struct Adder {
    a: u32
}

impl FnOnce<(u32, )> for Adder {
    type Output = u32;
    extern "rust-call" fn call_once(self, b: (u32, )) -> Self::Output {
        self.a + b.0
    }
}

fn main() {
    let adder = Adder { a: 3 };
    assert_eq!(adder(2), 5);
}

forget_unsized

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


format_args_nl

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


fs_try_exists

The tracking issue for this feature is: #83186


future_join

The tracking issue for this feature is: #91642


gen_future

The tracking issue for this feature is: #50547


generator_trait

The tracking issue for this feature is: #43122


generic_assert_internals

The tracking issue for this feature is: #44838


get_mut_unchecked

The tracking issue for this feature is: #63292


hash_drain_filter

The tracking issue for this feature is: #59618


hash_raw_entry

The tracking issue for this feature is: #56167


hash_set_entry

The tracking issue for this feature is: #60896


hasher_prefixfree_extras

The tracking issue for this feature is: #96762


hashmap_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


hint_must_use

The tracking issue for this feature is: #94745


inplace_iteration

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


int_error_internals

This feature is internal to the Rust compiler and is not intended for general use.


int_log

The tracking issue for this feature is: #70887


int_roundings

The tracking issue for this feature is: #88581


integer_atomics

The tracking issue for this feature is: #99069


internal_output_capture

This feature is internal to the Rust compiler and is not intended for general use.


io_error_downcast

The tracking issue for this feature is: #99262


io_error_more

The tracking issue for this feature is: #86442


io_error_other

The tracking issue for this feature is: #91946


io_error_uncategorized

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


io_slice_advance

The tracking issue for this feature is: #62726


ip

The tracking issue for this feature is: #27709


is_some_with

The tracking issue for this feature is: #93050


is_sorted

The tracking issue for this feature is: #53485


Add the methods is_sorted, is_sorted_by and is_sorted_by_key to [T]; add the methods is_sorted, is_sorted_by and is_sorted_by_key to Iterator.

iter_advance_by

The tracking issue for this feature is: #77404


iter_array_chunks

The tracking issue for this feature is: #100450


iter_collect_into

The tracking issue for this feature is: #94780


iter_from_generator

The tracking issue for this feature is: #43122


iter_intersperse

The tracking issue for this feature is: #79524


iter_is_partitioned

The tracking issue for this feature is: #62544


iter_next_chunk

The tracking issue for this feature is: #98326


iter_order_by

The tracking issue for this feature is: #64295


iter_partition_in_place

The tracking issue for this feature is: #62543


iterator_try_collect

The tracking issue for this feature is: #94047


iterator_try_reduce

The tracking issue for this feature is: #87053


layout_for_ptr

The tracking issue for this feature is: #69835


liballoc_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


libstd_sys_internals

This feature is internal to the Rust compiler and is not intended for general use.


libstd_thread_internals

This feature is internal to the Rust compiler and is not intended for general use.


linked_list_cursors

The tracking issue for this feature is: #58533


linked_list_remove

The tracking issue for this feature is: #69210


linux_pidfd

The tracking issue for this feature is: #82971


local_key_cell_methods

The tracking issue for this feature is: #92122


log_syntax

The tracking issue for this feature is: #29598


main_separator_str

The tracking issue for this feature is: #94071


map_entry_replace

The tracking issue for this feature is: #44286


map_first_last

The tracking issue for this feature is: #62924


map_many_mut

The tracking issue for this feature is: #97601


map_try_insert

The tracking issue for this feature is: #82766


maybe_uninit_array_assume_init

The tracking issue for this feature is: #96097


maybe_uninit_as_bytes

The tracking issue for this feature is: #93092


maybe_uninit_slice

The tracking issue for this feature is: #63569


maybe_uninit_uninit_array

The tracking issue for this feature is: #96097


maybe_uninit_write_slice

The tracking issue for this feature is: #79995


mem_copy_fn

The tracking issue for this feature is: #98262


mixed_integer_ops

The tracking issue for this feature is: #87840


mutex_unlock

The tracking issue for this feature is: #81872


mutex_unpoison

The tracking issue for this feature is: #96469


new_uninit

The tracking issue for this feature is: #63291


nonnull_slice_from_raw_parts

The tracking issue for this feature is: #71941


nonzero_bits

The tracking issue for this feature is: #94881


nonzero_min_max

The tracking issue for this feature is: #89065


nonzero_ops

The tracking issue for this feature is: #84186


numfmt

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


once_cell

The tracking issue for this feature is: #74465


one_sided_range

The tracking issue for this feature is: #69780


option_get_or_insert_default

The tracking issue for this feature is: #82901


option_result_contains

The tracking issue for this feature is: #62358


option_zip

The tracking issue for this feature is: #70086


panic_abort

The tracking issue for this feature is: #32837


panic_always_abort

The tracking issue for this feature is: #84438


panic_backtrace_config

The tracking issue for this feature is: #93346


panic_can_unwind

The tracking issue for this feature is: #92988


panic_info_message

The tracking issue for this feature is: #66745


panic_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


panic_unwind

The tracking issue for this feature is: #32837


panic_update_hook

The tracking issue for this feature is: #92649


path_file_prefix

The tracking issue for this feature is: #86319


pattern

The tracking issue for this feature is: #27721


peer_credentials_unix_socket

The tracking issue for this feature is: #42839


pin_deref_mut

The tracking issue for this feature is: #86918


pin_macro

The tracking issue for this feature is: #93178


pointer_byte_offsets

The tracking issue for this feature is: #96283


pointer_is_aligned

The tracking issue for this feature is: #96284


poll_ready

The tracking issue for this feature is: #89780


portable_simd

The tracking issue for this feature is: #86656


prelude_2024

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


print_internals

This feature is internal to the Rust compiler and is not intended for general use.


proc_macro_def_site

The tracking issue for this feature is: #54724


proc_macro_diagnostic

The tracking issue for this feature is: #54140


proc_macro_expand

The tracking issue for this feature is: #90765


proc_macro_internals

The tracking issue for this feature is: #27812


proc_macro_quote

The tracking issue for this feature is: #54722


proc_macro_span

The tracking issue for this feature is: #54725


proc_macro_span_shrink

The tracking issue for this feature is: #87552


proc_macro_tracked_env

The tracking issue for this feature is: #99515


process_exitcode_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


process_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


profiler_runtime_lib

This feature is internal to the Rust compiler and is not intended for general use.


provide_any

The tracking issue for this feature is: #96024


ptr_as_uninit

The tracking issue for this feature is: #75402


ptr_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


ptr_mask

The tracking issue for this feature is: #98290


ptr_metadata

The tracking issue for this feature is: #81513


ptr_sub_ptr

The tracking issue for this feature is: #95892


ptr_to_from_bits

The tracking issue for this feature is: #91126


pub_crate_should_not_need_unstable_attr

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


raw_os_nonzero

The tracking issue for this feature is: #82363


raw_slice_split

The tracking issue for this feature is: #95595


raw_vec_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


read_buf

The tracking issue for this feature is: #78485


receiver_trait

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


restricted_std

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


result_contains_err

The tracking issue for this feature is: #62358


result_flattening

The tracking issue for this feature is: #70142


result_option_inspect

The tracking issue for this feature is: #91345


round_char_boundary

The tracking issue for this feature is: #93743


rt

This feature is internal to the Rust compiler and is not intended for general use.


saturating_int_assign_impl

The tracking issue for this feature is: #92354


saturating_int_impl

The tracking issue for this feature is: #87920


sealed

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


seek_stream_len

The tracking issue for this feature is: #59359


set_ptr_value

The tracking issue for this feature is: #75091


setgroups

The tracking issue for this feature is: #90747


sgx_platform

The tracking issue for this feature is: #56975


slice_as_chunks

The tracking issue for this feature is: #74985


slice_concat_ext

The tracking issue for this feature is: #27747


slice_concat_trait

The tracking issue for this feature is: #27747


slice_flatten

The tracking issue for this feature is: #95629


slice_from_ptr_range

The tracking issue for this feature is: #89792


slice_group_by

The tracking issue for this feature is: #80552


slice_index_methods

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


slice_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


slice_iter_mut_as_mut_slice

The tracking issue for this feature is: #93079


slice_partition_dedup

The tracking issue for this feature is: #54279


slice_pattern

The tracking issue for this feature is: #56345


slice_ptr_get

The tracking issue for this feature is: #74265


slice_ptr_len

The tracking issue for this feature is: #71146


slice_range

The tracking issue for this feature is: #76393


slice_split_at_unchecked

The tracking issue for this feature is: #76014


slice_swap_unchecked

The tracking issue for this feature is: #88539


slice_take

The tracking issue for this feature is: #62280


solid_ext

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


sort_floats

The tracking issue for this feature is: #93396


sort_internals

This feature is internal to the Rust compiler and is not intended for general use.


split_array

The tracking issue for this feature is: #90091


split_as_slice

The tracking issue for this feature is: #96137


std_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


stdio_makes_pipe

The tracking issue for this feature is: #98288


stdsimd

The tracking issue for this feature is: #48556


step_trait

The tracking issue for this feature is: #42168


str_internals

This feature is internal to the Rust compiler and is not intended for general use.


str_split_as_str

The tracking issue for this feature is: #77998


str_split_inclusive_as_str

The tracking issue for this feature is: #77998


str_split_whitespace_as_str

The tracking issue for this feature is: #77998


strict_provenance_atomic_ptr

The tracking issue for this feature is: #99108


string_extend_from_within

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


string_remove_matches

The tracking issue for this feature is: #72826


sync_unsafe_cell

The tracking issue for this feature is: #95439


tcp_linger

The tracking issue for this feature is: #88494


tcp_quickack

The tracking issue for this feature is: #96256


tcplistener_into_incoming

The tracking issue for this feature is: #88339


test

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):

#![allow(unused)]
#![feature(test)]

fn main() {
extern crate test;

pub fn add_two(a: i32) -> i32 {
    a + 2
}

#[cfg(test)]
mod tests {
    use super::*;
    use test::Bencher;

    #[test]
    fn it_works() {
        assert_eq!(4, add_two(2));
    }

    #[bench]
    fn bench_add_two(b: &mut Bencher) {
        b.iter(|| add_two(2));
    }
}
}

Note the test feature gate, which enables this unstable feature.

We've imported the test crate, which contains our benchmarking support. We have a new function as well, with the bench attribute. Unlike regular tests, which take no arguments, benchmark tests take a &mut Bencher. This Bencher provides an iter method, which takes a closure. This closure contains the code we'd like to benchmark.

We can run benchmark tests with cargo bench:

$ cargo bench
   Compiling adder v0.0.1 (file:///home/steve/tmp/adder)
     Running target/release/adder-91b3e234d4ed382a

running 2 tests
test tests::it_works ... ignored
test tests::bench_add_two ... bench:         1 ns/iter (+/- 0)

test result: ok. 0 passed; 0 failed; 1 ignored; 1 measured

Our non-benchmark test was ignored. You may have noticed that cargo bench takes a bit longer than cargo test. This is because Rust runs our benchmark a number of times, and then takes the average. Because we're doing so little work in this example, we have a 1 ns/iter (+/- 0), but this would show the variance if there was one.

Advice on writing benchmarks:

  • Move setup code outside the iter loop; only put the part you want to measure inside
  • Make the code do "the same thing" on each iteration; do not accumulate or change state
  • Make the outer function idempotent too; the benchmark runner is likely to run it many times
  • Make the inner iter loop short and fast so benchmark runs are fast and the calibrator can adjust the run-length at fine resolution
  • Make the code in the iter loop do something simple, to assist in pinpointing performance improvements (or regressions)

Gotcha: optimizations

There's another tricky part to writing benchmarks: benchmarks compiled with optimizations activated can be dramatically changed by the optimizer so that the benchmark is no longer benchmarking what one expects. For example, the compiler might recognize that some calculation has no external effects and remove it entirely.

#![allow(unused)]
#![feature(test)]

fn main() {
extern crate test;
use test::Bencher;

#[bench]
fn bench_xor_1000_ints(b: &mut Bencher) {
    b.iter(|| {
        (0..1000).fold(0, |old, new| old ^ new);
    });
}
}

gives the following results

running 1 test
test bench_xor_1000_ints ... bench:         0 ns/iter (+/- 0)

test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured

The benchmarking runner offers two ways to avoid this. Either, the closure that the iter method receives can return an arbitrary value which forces the optimizer to consider the result used and ensures it cannot remove the computation entirely. This could be done for the example above by adjusting the b.iter call to

#![allow(unused)]
fn main() {
struct X;
impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
b.iter(|| {
    // Note lack of `;` (could also use an explicit `return`).
    (0..1000).fold(0, |old, new| old ^ new)
});
}

Or, the other option is to call the generic test::black_box function, which is an opaque "black box" to the optimizer and so forces it to consider any argument as used.

#![feature(test)]

extern crate test;

fn main() {
struct X;
impl X { fn iter<T, F>(&self, _: F) where F: FnMut() -> T {} } let b = X;
b.iter(|| {
    let n = test::black_box(1000);

    (0..n).fold(0, |a, b| a ^ b)
})
}

Neither of these read or modify the value, and are very cheap for small values. Larger values can be passed indirectly to reduce overhead (e.g. black_box(&huge_struct)).

Performing either of the above changes gives the following benchmarking results

running 1 test
test bench_xor_1000_ints ... bench:       131 ns/iter (+/- 3)

test result: ok. 0 passed; 0 failed; 0 ignored; 1 measured

However, the optimizer can still modify a testcase in an undesirable manner even when using either of the above.

thin_box

The tracking issue for this feature is: #92791


thread_id_value

The tracking issue for this feature is: #67939


thread_local_internals

This feature is internal to the Rust compiler and is not intended for general use.


thread_spawn_unchecked

The tracking issue for this feature is: #55132


trace_macros

The tracking issue for this feature is #29598.


With trace_macros you can trace the expansion of macros in your code.

Examples

#![feature(trace_macros)]

fn main() {
    trace_macros!(true);
    println!("Hello, Rust!");
    trace_macros!(false);
}

The cargo build output:

note: trace_macro
 --> src/main.rs:5:5
  |
5 |     println!("Hello, Rust!");
  |     ^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: expanding `println! { "Hello, Rust!" }`
  = note: to `print ! ( concat ! ( "Hello, Rust!" , "\n" ) )`
  = note: expanding `print! { concat ! ( "Hello, Rust!" , "\n" ) }`
  = note: to `$crate :: io :: _print ( format_args ! ( concat ! ( "Hello, Rust!" , "\n" ) )
          )`

    Finished dev [unoptimized + debuginfo] target(s) in 0.60 secs

track_path

The tracking issue for this feature is: #99515


transmutability

The tracking issue for this feature is: #99571


trusted_len

The tracking issue for this feature is: #37572


trusted_random_access

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


trusted_step

The tracking issue for this feature is: #85731


try_find

The tracking issue for this feature is: #63178


try_reserve_kind

The tracking issue for this feature is: #48043


try_trait_v2

The tracking issue for this feature is: #84277


try_trait_v2_residual

The tracking issue for this feature is: #91285


try_trait_v2_yeet

The tracking issue for this feature is: #96374


tuple_trait

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


type_name_of_val

The tracking issue for this feature is: #66359


unchecked_math

The tracking issue for this feature is: #85122


unicode_internals

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


unix_chown

The tracking issue for this feature is: #88989


unix_set_mark

The tracking issue for this feature is: #96467


unix_socket_abstract

The tracking issue for this feature is: #85410


unix_socket_ancillary_data

The tracking issue for this feature is: #76915


unix_socket_peek

The tracking issue for this feature is: #76923


unsize

The tracking issue for this feature is: #27732


unwrap_infallible

The tracking issue for this feature is: #61695


unzip_option

The tracking issue for this feature is: #87800


update_panic_count

This feature is internal to the Rust compiler and is not intended for general use.


utf16_extra

The tracking issue for this feature is: #94919


utf16_extra_const

The tracking issue for this feature is: #94919


utf8_chunks

The tracking issue for this feature is: #99543


variant_count

The tracking issue for this feature is: #73662


vec_into_raw_parts

The tracking issue for this feature is: #65816


vec_split_at_spare

The tracking issue for this feature is: #81944


waker_getters

The tracking issue for this feature is: #87021


wasi_ext

The tracking issue for this feature is: #71213


windows_by_handle

The tracking issue for this feature is: #63010


windows_c

This feature is internal to the Rust compiler and is not intended for general use.


windows_handle

This feature is internal to the Rust compiler and is not intended for general use.


windows_net

This feature is internal to the Rust compiler and is not intended for general use.


windows_process_exit_code_from

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.


windows_process_extensions_async_pipes

The tracking issue for this feature is: #98289


windows_process_extensions_force_quotes

The tracking issue for this feature is: #82227


windows_process_extensions_main_thread_handle

The tracking issue for this feature is: #96723


windows_stdio

This feature is internal to the Rust compiler and is not intended for general use.


wrapping_int_impl

The tracking issue for this feature is: #32463


wrapping_next_power_of_two

The tracking issue for this feature is: #32463


write_all_vectored

The tracking issue for this feature is: #70436


yeet_desugar_details

This feature has no tracking issue, and is therefore likely internal to the compiler, not being intended for general use.