Skip to content

Rollup of 6 pull requests #28875

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 10 commits into from
1 change: 1 addition & 0 deletions src/doc/index.md
Original file line number Diff line number Diff line change
Expand Up @@ -98,3 +98,4 @@ languages:
- [Korean](https://github.com/rust-kr/doc.rust-kr.org)
- [Chinese](https://github.com/KaiserY/rust-book-chinese)
- [Spanish](https://goyox86.github.io/elpr)
- [German](https://panicbit.github.io/rustbook-de)
1 change: 1 addition & 0 deletions src/doc/trpl/SUMMARY.md
Original file line number Diff line number Diff line change
Expand Up @@ -68,5 +68,6 @@
* [Box Syntax and Patterns](box-syntax-and-patterns.md)
* [Slice Patterns](slice-patterns.md)
* [Associated Constants](associated-constants.md)
* [Custom Allocators](custom-allocators.md)
* [Glossary](glossary.md)
* [Bibliography](bibliography.md)
169 changes: 169 additions & 0 deletions src/doc/trpl/custom-allocators.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,169 @@
% Custom Allocators

Allocating memory isn't always the easiest thing to do, and while Rust generally
takes care of this by default it often becomes necessary to customize how
allocation occurs. The compiler and standard library currently allow switching
out the default global allocator in use at compile time. The design is currently
spelled out in [RFC 1183][rfc] but this will walk you through how to get your
own allocator up and running.

[rfc]: https://github.com/rust-lang/rfcs/blob/master/text/1183-swap-out-jemalloc.md

# Default Allocator

The compiler currently ships two default allocators: `alloc_system` and
`alloc_jemalloc` (some targets don't have jemalloc, however). These allocators
are just normal Rust crates and contain an implementation of the routines to
allocate and deallocate memory. The standard library is not compiled assuming
either one, and the compiler will decide which allocator is in use at
compile-time depending on the type of output artifact being produced.

Binaries generated by the compiler will use `alloc_jemalloc` by default (where
available). In this situation the compiler "controls the world" in the sense of
it has power over the final link. Primarily this means that the allocator
decision can be left up the compiler.

Dynamic and static libraries, however, will use `alloc_system` by default. Here
Rust is typically a 'guest' in another application or another world where it
cannot authoritatively decide what allocator is in use. As a result it resorts
back to the standard APIs (e.g. `malloc` and `free`) for acquiring and releasing
memory.

# Switching Allocators

Although the compiler's default choices may work most of the time, it's often
necessary to tweak certain aspects. Overriding the compiler's decision about
which allocator is in use is done simply by linking to the desired allocator:

```rust,no_run
#![feature(alloc_system)]

extern crate alloc_system;

fn main() {
let a = Box::new(4); // allocates from the system allocator
println!("{}", a);
}
```

In this example the binary generated will not link to jemalloc by default but
instead use the system allocator. Conversely to generate a dynamic library which
uses jemalloc by default one would write:

```rust,no_run
#![feature(alloc_jemalloc)]
#![crate_type = "dylib"]

extern crate alloc_jemalloc;

pub fn foo() {
let a = Box::new(4); // allocates from jemalloc
println!("{}", a);
}
# fn main() {}
```

# Writing a custom allocator

Sometimes even the choices of jemalloc vs the system allocator aren't enough and
an entirely new custom allocator is required. In this you'll write your own
crate which implements the allocator API (e.g. the same as `alloc_system` or
`alloc_jemalloc`). As an example, let's take a look at a simplified and
annotated version of `alloc_system`

```rust,no_run
# // only needed for rustdoc --test down below
# #![feature(lang_items)]
// The compiler needs to be instructed that this crate is an allocator in order
// to realize that when this is linked in another allocator like jemalloc should
// not be linked in
#![feature(allocator)]
#![allocator]

// Allocators are not allowed to depend on the standard library which in turn
// requires an allocator in order to avoid circular dependencies. This crate,
// however, can use all of libcore.
#![feature(no_std)]
#![no_std]

// Let's give a unique name to our custom allocator
#![crate_name = "my_allocator"]
#![crate_type = "rlib"]

// Our system allocator will use the in-tree libc crate for FFI bindings. Note
// that currently the external (crates.io) libc cannot be used because it links
// to the standard library (e.g. `#![no_std]` isn't stable yet), so that's why
// this specifically requires the in-tree version.
#![feature(libc)]
extern crate libc;

// Listed below are the five allocation functions currently required by custom
// allocators. Their signatures and symbol names are not currently typechecked
// by the compiler, but this is a future extension and are required to match
// what is found below.
//
// Note that the standard `malloc` and `realloc` functions do not provide a way
// to communicate alignment so this implementation would need to be improved
// with respect to alignment in that aspect.

#[no_mangle]
pub extern fn __rust_allocate(size: usize, _align: usize) -> *mut u8 {
unsafe { libc::malloc(size as libc::size_t) as *mut u8 }
}

#[no_mangle]
pub extern fn __rust_deallocate(ptr: *mut u8, _old_size: usize, _align: usize) {
unsafe { libc::free(ptr as *mut libc::c_void) }
}

#[no_mangle]
pub extern fn __rust_reallocate(ptr: *mut u8, _old_size: usize, size: usize,
_align: usize) -> *mut u8 {
unsafe {
libc::realloc(ptr as *mut libc::c_void, size as libc::size_t) as *mut u8
}
}

#[no_mangle]
pub extern fn __rust_reallocate_inplace(_ptr: *mut u8, old_size: usize,
_size: usize, _align: usize) -> usize {
old_size // this api is not supported by libc
}

#[no_mangle]
pub extern fn __rust_usable_size(size: usize, _align: usize) -> usize {
size
}

# // just needed to get rustdoc to test this
# fn main() {}
# #[lang = "panic_fmt"] fn panic_fmt() {}
# #[lang = "eh_personality"] fn eh_personality() {}
```

After we compile this crate, it can be used as follows:

```rust,ignore
extern crate my_allocator;

fn main() {
let a = Box::new(8); // allocates memory via our custom allocator crate
println!("{}", a);
}
```

# Custom allocator limitations

There are a few restrictions when working with custom allocators which may cause
compiler errors:

* Any one artifact may only be linked to at most one allocator. Binaries,
dylibs, and staticlibs must link to exactly one allocator, and if none have
been explicitly chosen the compiler will choose one. On the other than rlibs
do not need to link to an allocator (but still can).

* A consumer of an allocator is tagged with `#![needs_allocator]` (e.g. the
`liballoc` crate currently) and an `#[allocator]` crate cannot transitively
depend on a crate which needs an allocator (e.g. circular dependencies are not
allowed). This basically means that allocators must restrict themselves to
libcore currently.
4 changes: 4 additions & 0 deletions src/libcollections/str.rs
Original file line number Diff line number Diff line change
Expand Up @@ -867,6 +867,10 @@ impl str {
/// ```rust,ignore
/// assert_eq!(d, &["a", "b", "c"]);
/// ```
///
/// Use [`.split_whitespace()`][split_whitespace] for this behavior.
///
/// [split_whitespace]: #method.split_whitespace
#[stable(feature = "rust1", since = "1.0.0")]
pub fn split<'a, P: Pattern<'a>>(&'a self, pat: P) -> Split<'a, P> {
core_str::StrExt::split(self, pat)
Expand Down
34 changes: 33 additions & 1 deletion src/librustc/diagnostics.rs
Original file line number Diff line number Diff line change
Expand Up @@ -1992,6 +1992,39 @@ static A : &'static u32 = &S.a; // ok!
```
"##,

E0496: r##"
A lifetime name is shadowing another lifetime name. Erroneous code example:

```
struct Foo<'a> {
a: &'a i32,
}

impl<'a> Foo<'a> {
fn f<'a>(x: &'a i32) { // error: lifetime name `'a` shadows a lifetime
// name that is already in scope
}
}
```

Please change the name of one of the lifetimes to remove this error. Example:


```
struct Foo<'a> {
a: &'a i32,
}

impl<'a> Foo<'a> {
fn f<'b>(x: &'b i32) { // ok!
}
}

fn main() {
}
```
"##,

E0497: r##"
A stability attribute was used outside of the standard library. Erroneous code
example:
Expand Down Expand Up @@ -2072,7 +2105,6 @@ register_diagnostics! {
E0491, // in type `..`, reference has a longer lifetime than the data it...
E0492, // cannot borrow a constant which contains interior mutability
E0495, // cannot infer an appropriate lifetime due to conflicting requirements
E0496, // .. name `..` shadows a .. name that is already in scope
E0498, // malformed plugin attribute
E0514, // metadata version mismatch
}
2 changes: 1 addition & 1 deletion src/librustc_trans/trans/consts.rs
Original file line number Diff line number Diff line change
Expand Up @@ -630,7 +630,7 @@ fn const_expr_unadjusted<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
// pass. Reporting here is a bit late.
cx.sess().span_err(e.span,
"const index-expr is out of bounds");
C_undef(type_of::type_of(cx, bt).element_type())
C_undef(val_ty(arr).element_type())
} else {
const_get_elt(cx, arr, &[iv as c_uint])
}
Expand Down
16 changes: 16 additions & 0 deletions src/test/compile-fail/const-slice-oob.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
// Copyright 2015 The Rust Project Developers. See the COPYRIGHT
// file at the top-level directory of this distribution and at
// http://rust-lang.org/COPYRIGHT.
//
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
// option. This file may not be copied, modified, or distributed
// except according to those terms.

const FOO: &'static[u32] = &[1, 2, 3];
const BAR: u32 = FOO[5]; //~ ERROR const index-expr is out of bounds

fn main() {
let _ = BAR;
}