diff --git a/src/doc/reference.md b/src/doc/reference.md index 66a7f543ad95f2337604a5e4d3f81096704054c9..750179622746936820b0b088fb3ee99035330a63 100644 --- a/src/doc/reference.md +++ b/src/doc/reference.md @@ -31,23 +31,27 @@ You may also be interested in the [grammar]. ## Unicode productions -A few productions in Rust's grammar permit Unicode code points outside the ASCII -range. We define these productions in terms of character properties specified -in the Unicode standard, rather than in terms of ASCII-range code points. The -section [Special Unicode Productions](#special-unicode-productions) lists these -productions. +A few productions in Rust's grammar permit Unicode code points outside the +ASCII range. We define these productions in terms of character properties +specified in the Unicode standard, rather than in terms of ASCII-range code +points. The grammar has a [Special Unicode Productions][unicodeproductions] +section that lists these productions. + +[unicodeproductions]: grammar.html#special-unicode-productions ## String table productions Some rules in the grammar — notably [unary operators](#unary-operator-expressions), [binary -operators](#binary-operator-expressions), and [keywords](#keywords) — are +operators](#binary-operator-expressions), and [keywords][keywords] — are given in a simplified form: as a listing of a table of unquoted, printable whitespace-separated strings. These cases form a subset of the rules regarding the [token](#tokens) rule, and are assumed to be the result of a lexical-analysis phase feeding the parser, driven by a DFA, operating over the disjunction of all such string table entries. +[keywords]: grammar.html#keywords + When such a string enclosed in double-quotes (`"`) occurs inside the grammar, it is an implicit reference to a single member of such a string table production. See [tokens](#tokens) for more information. @@ -75,7 +79,7 @@ An identifier is any nonempty Unicode[^non_ascii_idents] string of the following - The first character has property `XID_start` - The remaining characters have property `XID_continue` -that does _not_ occur in the set of [keywords](#keywords). +that does _not_ occur in the set of [keywords][keywords]. > **Note**: `XID_start` and `XID_continue` as character properties cover the > character ranges used to form the more familiar C and Java language-family @@ -401,7 +405,7 @@ Symbols are a general class of printable [token](#tokens) that play structural roles in a variety of grammar productions. They are catalogued here for completeness as the set of remaining miscellaneous printable tokens that do not otherwise appear as [unary operators](#unary-operator-expressions), [binary -operators](#binary-operator-expressions), or [keywords](#keywords). +operators](#binary-operator-expressions), or [keywords][keywords]. ## Paths @@ -547,7 +551,7 @@ _name_ s that occur in its body. At the "current layer", they all must repeat the same number of times, so ` ( $( $i:ident ),* ; $( $j:ident ),* ) => ( $( ($i,$j) ),* )` is valid if given the argument `(a,b,c ; d,e,f)`, but not `(a,b,c ; d,e)`. The repetition walks through the choices at that layer in -lockstep, so the former input transcribes to `( (a,d), (b,e), (c,f) )`. +lockstep, so the former input transcribes to `(a,d), (b,e), (c,f)`. Nested repetitions are allowed. @@ -611,7 +615,7 @@ module needs its own source file: [module definitions](#modules) can be nested within one file. Each source file contains a sequence of zero or more `item` definitions, and -may optionally begin with any number of [attributes](#Items and attributes) +may optionally begin with any number of [attributes](#items-and-attributes) that apply to the containing module, most of which influence the behavior of the compiler. The anonymous crate module can have additional attributes that apply to the crate as a whole. @@ -653,7 +657,7 @@ There are several kinds of item: * [`use` declarations](#use-declarations) * [modules](#modules) * [functions](#functions) -* [type aliases](#type-aliases) +* [type definitions](grammar.html#type-definitions) * [structures](#structures) * [enumerations](#enumerations) * [constant items](#constant-items) @@ -773,7 +777,7 @@ extern crate std as ruststd; // linking to 'std' under another name A _use declaration_ creates one or more local name bindings synonymous with some other [path](#paths). Usually a `use` declaration is used to shorten the path required to refer to a module item. These declarations may appear at the -top of [modules](#modules) and [blocks](#blocks). +top of [modules](#modules) and [blocks](grammar.html#block-expressions). > **Note**: Unlike in many languages, > `use` declarations in Rust do *not* declare linkage dependency with external crates. @@ -1144,9 +1148,7 @@ let px: i32 = match p { Point(x, _) => x }; ``` A _unit-like struct_ is a structure without any fields, defined by leaving off -the list of fields entirely. Such types will have a single value, just like -the [unit value `()`](#unit-and-boolean-literals) of the unit type. For -example: +the list of fields entirely. Such types will have a single value. For example: ``` struct Cookie; @@ -2436,11 +2438,6 @@ comma: (0); // zero in parentheses ``` -### Unit expressions - -The expression `()` denotes the _unit value_, the only value of the type with -the same name. - ### Structure expressions There are several forms of structure expressions. A _structure expression_ @@ -3281,7 +3278,7 @@ constructor or `struct` field may refer, directly or indirectly, to the enclosing `enum` or `struct` type itself. Such recursion has restrictions: * Recursive types must include a nominal type in the recursion - (not mere [type definitions](#type-definitions), + (not mere [type definitions](grammar.html#type-definitions), or other structural types such as [arrays](#array,-and-slice-types) or [tuples](#tuple-types)). * A recursive `enum` item must have at least one non-recursive constructor (in order to give the recursion a basis case). diff --git a/src/doc/trpl/compiler-plugins.md b/src/doc/trpl/compiler-plugins.md index 9eb22a7f6985a51bb6e026aaf73896f1a630135a..127e097c34f7db03ef946a34e4fd8f168821ca31 100644 --- a/src/doc/trpl/compiler-plugins.md +++ b/src/doc/trpl/compiler-plugins.md @@ -176,7 +176,7 @@ for a full example, the core of which is reproduced here: ```ignore declare_lint!(TEST_LINT, Warn, - "Warn about items named 'lintme'") + "Warn about items named 'lintme'"); struct Pass; diff --git a/src/doc/trpl/method-syntax.md b/src/doc/trpl/method-syntax.md index c5dd25516f3196087a7e0b8406ead3fb920b8944..1527d9cf978df96af30197592a36ab15f1cd015a 100644 --- a/src/doc/trpl/method-syntax.md +++ b/src/doc/trpl/method-syntax.md @@ -127,12 +127,12 @@ fn grow(&self) -> Circle { We just say we’re returning a `Circle`. With this method, we can grow a new circle to any arbitrary size. -# Static methods +# Associated functions -You can also define static methods that do not take a `self` parameter. Here’s a -pattern that’s very common in Rust code: +You can also define associated functions that do not take a `self` parameter. +Here’s a pattern that’s very common in Rust code: -``` +```rust struct Circle { x: f64, y: f64, diff --git a/src/doc/trpl/the-stack-and-the-heap.md b/src/doc/trpl/the-stack-and-the-heap.md index cc0941bc025aa55caa09d83c0b6874604648d8d1..7b1cd7dc8093b3646730023c36a5a12c5e1570c5 100644 --- a/src/doc/trpl/the-stack-and-the-heap.md +++ b/src/doc/trpl/the-stack-and-the-heap.md @@ -1,3 +1,570 @@ % The Stack and the Heap -Coming Soon +As a systems language, Rust operates at a low level. If you’re coming from a +high-level language, there are some aspects of systems programming that you may +not be familiar with. The most important one is how memory works, with a stack +and a heap. If you’re familiar with how C-like languages use stack allocation, +this chapter will be a refresher. If you’re not, you’ll learn about this more +general concept, but with a Rust-y focus. + +# Memory management + +These two terms are about memory management. The stack and the heap are +abstractions that help you determine when to allocate and deallocate memory. + +Here’s a high-level comparison: + +The stack is very fast, and is where memory is allocated in Rust by default. +But the allocation is local to a function call, and is limited in size. The +heap, on the other hand, is slower, and is explicitly allocated by your +program. But it’s effectively unlimited in size, and is globally accessible. + +# The Stack + +Let’s talk about this Rust program: + +```rust +fn main() { + let x = 42; +} +``` + +This program has one variable binding, `x`. This memory needs to be allocated +from somewhere. Rust ‘stack allocates’ by default, which means that basic +values ‘go on the stack’. What does that mean? + +Well, when a function gets called, some memory gets allocated for all of its +local variables and some other information. This is called a ‘stack frame’, and +for the purpose of this tutorial, we’re going to ignore the extra information +and just consider the local variables we’re allocating. So in this case, when +`main()` is run, we’ll allocate a single 32-bit integer for our stack frame. +This is automatically handled for you, as you can see, we didn’t have to write +any special Rust code or anything. + +When the function is over, its stack frame gets deallocated. This happens +automatically, we didn’t have to do anything special here. + +That’s all there is for this simple program. The key thing to understand here +is that stack allocation is very, very fast. Since we know all the local +variables we have ahead of time, we can grab the memory all at once. And since +we’ll throw them all away at the same time as well, we can get rid of it very +fast too. + +The downside is that we can’t keep values around if we need them for longer +than a single function. We also haven’t talked about what that name, ‘stack’ +means. To do that, we need a slightly more complicated example: + +```rust +fn foo() { + let y = 5; + let z = 100; +} + +fn main() { + let x = 42; + + foo(); +} +``` + +This program has three variables total: two in `foo()`, one in `main()`. Just +as before, when `main()` is called, a single integer is allocated for its stack +frame. But before we can show what happens when `foo()` is called, we need to +visualize what’s going on with memory. Your operating system presents a view of +memory to your program that’s pretty simple: a huge list of addresses, from 0 +to a large number, representing how much RAM your computer has. For example, if +you have a gigabyte of RAM, your addresses go from `0` to `1,073,741,824`. That +number comes from 230, the number of bytes in a gigabyte. + +This memory is kind of like a giant array: addresses start at zero and go +up to the final number. So here’s a diagram of our first stack frame: + +| Address | Name | Value | ++---------+------+-------+ +| 0 | x | 42 | + +We’ve got `x` located at address `0`, with the value `42`. + +When `foo()` is called, a new stack frame is allocated: + +| Address | Name | Value | ++---------+------+-------+ +| 2 | z | 100 | +| 1 | y | 5 | +| 0 | x | 42 | + +Because `0` was taken by the first frame, `1` and `2` are used for `foo()`’s +stack frame. It grows upward, the more functions we call. + + +There’s some important things we have to take note of here. The numbers 0, 1, +and 2 are all solely for illustrative purposes, and bear no relationship to the +actual numbers the computer will actually use. In particular, the series of +addresses are in reality going to be separated by some number of bytes that +separate each address, and that separation may even exceed the size of the +value being stored. + +After `foo()` is over, its frame is deallocated: + +| Address | Name | Value | ++---------+------+-------+ +| 0 | x | 42 | + +And then, after `main()`, even this last value goes away. Easy! + +It’s called a ‘stack’ because it works like a stack of dinner plates: the first +plate you put down is the last plate to pick back up. Stacks are sometimes +called ‘last in, first out queues’ for this reason, as the last value you put +on the stack is the first one you retrieve from it. + +Let’s try a three-deep example: + +```rust +fn bar() { + let i = 6; +} + +fn foo() { + let a = 5; + let b = 100; + let c = 1; + + bar(); +} + +fn main() { + let x = 42; + + foo(); +} +``` + +Okay, first, we call `main()`: + +| Address | Name | Value | ++---------+------+-------+ +| 0 | x | 42 | + +Next up, `main()` calls `foo()`: + +| Address | Name | Value | ++---------+------+-------+ +| 3 | c | 1 | +| 2 | b | 100 | +| 1 | a | 5 | +| 0 | x | 42 | + +And then `foo()` calls `bar()`: + +| Address | Name | Value | ++---------+------+-------+ +| 4 | i | 6 | +| 3 | c | 1 | +| 2 | b | 100 | +| 1 | a | 5 | +| 0 | x | 42 | + +Whew! Our stack is growing tall. + +After `bar()` is over, its frame is deallocated, leaving just `foo()` and +`main()`: + +| Address | Name | Value | ++---------+------+-------+ +| 3 | c | 1 | +| 2 | b | 100 | +| 1 | a | 5 | +| 0 | x | 42 | + +And then `foo()` ends, leaving just `main()` + +| Address | Name | Value | ++---------+------+-------+ +| 0 | x | 42 | + +And then we’re done. Getting the hang of it? It’s like piling up dishes: you +add to the top, you take away from the top. + +# The Heap + +Now, this works pretty well, but not everything can work like this. Sometimes, +you need to pass some memory between different functions, or keep it alive for +longer than a single function’s execution. For this, we can use the heap. + +In Rust, you can allocate memory on the heap with the [`Box` type][box]. +Here’s an example: + +```rust +fn main() { + let x = Box::new(5); + let y = 42; +} +``` + +[box]: ../std/boxed/index.html + +Here’s what happens in memory when `main()` is called: + +| Address | Name | Value | ++---------+------+--------+ +| 1 | y | 42 | +| 0 | x | ?????? | + +We allocate space for two variables on the stack. `y` is `42`, as it always has +been, but what about `x`? Well, `x` is a `Box`, and boxes allocate memory +on the heap. The actual value of the box is a structure which has a pointer to +‘the heap’. When we start executing the function, and `Box::new()` is called, +it allocates some memory for the heap, and puts `5` there. The memory now looks +like this: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 230 | | 5 | +| ... | ... | ... | +| 1 | y | 42 | +| 0 | x | 230 | + +We have 230 in our hypothetical computer with 1GB of RAM. And since +our stack grows from zero, the easiest place to allocate memory is from the +other end. So our first value is at the highest place in memory. And the value +of the struct at `x` has a [raw pointer][rawpointer] to the place we’ve +allocated on the heap, so the value of `x` is 230, the memory +location we’ve asked for. + +[rawpointer]: raw-pointers.html + +We haven’t really talked too much about what it actually means to allocate and +deallocate memory in these contexts. Getting into very deep detail is out of +the scope of this tutorial, but what’s important to point out here is that +the heap isn’t just a stack that grows from the opposite end. We’ll have an +example of this later in the book, but because the heap can be allocated and +freed in any order, it can end up with ‘holes’. Here’s a diagram of the memory +layout of a program which has been running for a while now: + + +| Address | Name | Value | ++----------------------+------+----------------------+ +| 230 | | 5 | +| (230) - 1 | | | +| (230) - 2 | | | +| (230) - 3 | | 42 | +| ... | ... | ... | +| 3 | y | (230) - 3 | +| 2 | y | 42 | +| 1 | y | 42 | +| 0 | x | 230 | + +In this case, we’ve allocated four things on the heap, but deallocated two of +them. There’s a gap between 230 and (230) - 3 which isn’t +currently being used. The specific details of how and why this happens depends +on what kind of strategy you use to manage the heap. Different programs can use +different ‘memory allocators’, which are libraries that manage this for you. +Rust programs use [jemalloc][jemalloc] for this purpose. + +[jemalloc]: http://www.canonware.com/jemalloc/ + +Anyway, back to our example. Since this memory is on the heap, it can stay +alive longer than the function which allocates the box. In this case, however, +it doesn’t.[^moving] When the function is over, we need to free the stack frame +for `main()`. `Box`, though, has a trick up its sleve: [Drop][drop]. The +implementation of `Drop` for `Box` deallocates the memory that was allocated +when it was created. Great! So when `x` goes away, it first frees the memory +allocated on the heap: + +| Address | Name | Value | ++---------+------+--------+ +| 1 | y | 42 | +| 0 | x | ?????? | + +[drop]: drop.html +[moving]: We can make the memory live longer by transferring ownership, + sometimes called ‘moving out of the box’. More complex examples will + be covered later. + + +And then the stack frame goes away, freeing all of our memory. + +# Arguments and borrowing + +We’ve got some basic examples with the stack and the heap going, but what about +function arguments and borrowing? Here’s a small Rust program: + +```rust +fn foo(i: &i32) { + let z = 42; +} + +fn main() { + let x = 5; + let y = &x; + + foo(y); +} +``` + +When we enter `main()`, memory looks like this: + +| Address | Name | Value | ++---------+------+-------+ +| 1 | y | 0 | +| 0 | x | 5 | + +`x` is a plain old `5`, and `y` is a reference to `x`. So its value is the +memory location that `x` lives at, which in this case is `0`. + +What about when we call `foo()`, passing `y` as an argument? + +| Address | Name | Value | ++---------+------+-------+ +| 3 | z | 42 | +| 2 | i | 0 | +| 1 | y | 0 | +| 0 | x | 5 | + +Stack frames aren’t just for local bindings, they’re for arguments too. So in +this case, we need to have both `i`, our argument, and `z`, our local variable +binding. `i` is a copy of the argument, `y`. Since `y`’s value is `0`, so is +`i`’s. + +This is one reason why borrowing a variable doesn’t deallocate any memory: the +value of a reference is just a pointer to a memory location. If we got rid of +the underlying memory, things wouldn’t work very well. + +# A complex example + +Okay, let’s go through this complex program step-by-step: + +```rust +fn foo(x: &i32) { + let y = 10; + let z = &y; + + baz(z); + bar(x, z); +} + +fn bar(a: &i32, b: &i32) { + let c = 5; + let d = Box::new(5); + let e = &d; + + baz(e); +} + +fn baz(f: &i32) { + let g = 100; +} + +fn main() { + let h = 3; + let i = Box::new(20); + let j = &h; + + foo(j); +} +``` + +First, we call `main()`: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 230 | | 20 | +| ... | ... | ... | +| 2 | j | 0 | +| 1 | i | 230 | +| 0 | h | 3 | + +We allocate memory for `j`, `i`, and `h`. `i` is on the heap, and so has a +value pointing there. + +Next, at the end of `main()`, `foo()` gets called: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 230 | | 20 | +| ... | ... | ... | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 230 | +| 0 | h | 3 | + +Space gets allocated for `x`, `y`, and `z`. The argument `x` has the same value +as `j`, since that’s what we passed it in. It’s a pointer to the `0` address, +since `j` points at `h`. + +Next, `foo()` calls `baz()`, passing `z`: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 230 | | 20 | +| ... | ... | ... | +| 7 | g | 100 | +| 6 | f | 4 | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 230 | +| 0 | h | 3 | + +We’ve allocated memory for `f` and `g`. `baz()` is very short, so when it’s +over, we get rid of its stack frame: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 230 | | 20 | +| ... | ... | ... | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 230 | +| 0 | h | 3 | + +Next, `foo()` calls `bar()` with `x` and `z`: + +| Address | Name | Value | ++----------------------+------+----------------------+ +| 230 | | 20 | +| (230) - 1 | | 5 | +| ... | ... | ... | +| 10 | e | 4 | +| 9 | d | (230) - 1 | +| 8 | c | 5 | +| 7 | b | 4 | +| 6 | a | 0 | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 230 | +| 0 | h | 3 | + +We end up allocating another value on the heap, and so we have to subtract one +from 230. It’s easier to just write that than `1,073,741,823`. In any +case, we set up the variables as usual. + +At the end of `bar()`, it calls `baz()`: + +| Address | Name | Value | ++----------------------+------+----------------------+ +| 230 | | 20 | +| (230) - 1 | | 5 | +| ... | ... | ... | +| 12 | g | 100 | +| 11 | f | 4 | +| 10 | e | 4 | +| 9 | d | (230) - 1 | +| 8 | c | 5 | +| 7 | b | 4 | +| 6 | a | 0 | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 230 | +| 0 | h | 3 | + +With this, we’re at our deepest point! Whew! Congrats for following along this +far. + +After `baz()` is over, we get rid of `f` and `g`: + +| Address | Name | Value | ++----------------------+------+----------------------+ +| 230 | | 20 | +| (230) - 1 | | 5 | +| ... | ... | ... | +| 10 | e | 4 | +| 9 | d | (230) - 1 | +| 8 | c | 5 | +| 7 | b | 4 | +| 6 | a | 0 | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 230 | +| 0 | h | 3 | + +Next, we return from `bar()`. `d` in this case is a `Box`, so it also frees +what it points to: (230) - 1. + +| Address | Name | Value | ++-----------------+------+----------------+ +| 230 | | 20 | +| ... | ... | ... | +| 5 | z | 4 | +| 4 | y | 10 | +| 3 | x | 0 | +| 2 | j | 0 | +| 1 | i | 230 | +| 0 | h | 3 | + +And after that, `foo()` returns: + +| Address | Name | Value | ++-----------------+------+----------------+ +| 230 | | 20 | +| ... | ... | ... | +| 2 | j | 0 | +| 1 | i | 230 | +| 0 | h | 3 | + +And then, finally, `main()`, which cleans the rest up. When `i` is `Drop`ped, +it will clean up the last of the heap too. + +# What do other languages do? + +Most languages with a garbage collector heap-allocate by default. This means +that every value is boxed. There are a number of reasons why this is done, but +they’re out of scope for this tutorial. There are some possible optimizations +that don’t make it true 100% of the time, too. Rather than relying on the stack +and `Drop` to clean up memory, the garbage collector deals with the heap +instead. + +# Which to use? + +So if the stack is faster and easier to manage, why do we need the heap? A big +reason is that Stack-allocation alone means you only have LIFO semantics for +reclaiming storage. Heap-allocation is strictly more general, allowing storage +to be taken from and returned to the pool in arbitrary order, but at a +complexity cost. + +Generally, you should prefer stack allocation, and so, Rust stack-allocates by +default. The LIFO model of the stack is simpler, at a fundamental level. This +has two big impacts: runtime efficiency and semantic impact. + +## Runtime Efficiency. + +Managing the memory for the stack is trivial: The machine just +increments or decrements a single value, the so-called “stack pointer”. +Managing memory for the heap is non-trivial: heap-allocated memory is freed at +arbitrary points, and each block of heap-allocated memory can be of arbitrary +size, the memory manager must generally work much harder to identify memory for +reuse. + +If you’d like to dive into this topic in greater detail, [this paper][wilson] +is a great introduction. + +[wilson]: http://www.cs.northwestern.edu/~pdinda/icsclass/doc/dsa.pdf + +## Semantic impact + +Stack-allocation impacts the Rust language itself, and thus the developer’s +mental model. The LIFO semantics is what drives how the Rust language handles +automatic memory management. Even the deallocation of a uniquely-owned +heap-allocated box can be driven by the stack-based LIFO semantics, as +discussed throughout this chapter. The flexibility (i.e. expressiveness) of non +LIFO-semantics means that in general the compiler cannot automatically infer at +compile-time where memory should be freed; it has to rely on dynamic protocols, +potentially from outside the language itself, to drive deallocation (reference +counting, as used by `Rc` and `Arc`, is one example of this). + +When taken to the extreme, the increased expressive power of heap allocation +comes at the cost of either significant runtime support (e.g. in the form of a +garbage collector) or significant programmer effort (in the form of explicit +memory management calls that require verification not provided by the Rust +compiler). diff --git a/src/liballoc/heap.rs b/src/liballoc/heap.rs index 83795a24c816066f17ed1997c7ca77e6aad03706..e155dc86f3251d497b43cea25c82ae1d503e9bd1 100644 --- a/src/liballoc/heap.rs +++ b/src/liballoc/heap.rs @@ -8,6 +8,15 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use core::{isize, usize}; + +#[inline(always)] +fn check_size_and_alignment(size: usize, align: usize) { + debug_assert!(size != 0); + debug_assert!(size <= isize::MAX as usize, "Tried to allocate too much: {} bytes", size); + debug_assert!(usize::is_power_of_two(align), "Invalid alignment of allocation: {}", align); +} + // FIXME: #13996: mark the `allocate` and `reallocate` return value as `noalias` /// Return a pointer to `size` bytes of memory aligned to `align`. @@ -19,6 +28,7 @@ /// size on the platform. #[inline] pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { + check_size_and_alignment(size, align); imp::allocate(size, align) } @@ -38,6 +48,7 @@ pub unsafe fn allocate(size: usize, align: usize) -> *mut u8 { /// any value in range_inclusive(requested_size, usable_size). #[inline] pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> *mut u8 { + check_size_and_alignment(size, align); imp::reallocate(ptr, old_size, size, align) } @@ -56,6 +67,7 @@ pub unsafe fn reallocate(ptr: *mut u8, old_size: usize, size: usize, align: usiz #[inline] pub unsafe fn reallocate_inplace(ptr: *mut u8, old_size: usize, size: usize, align: usize) -> usize { + check_size_and_alignment(size, align); imp::reallocate_inplace(ptr, old_size, size, align) } diff --git a/src/libcollections/bit.rs b/src/libcollections/bit.rs index 31cad0fdbb1a788c0fa861c7e1ad3efccbdab8b3..8ec4a68f2b14b7c6334a24f8a10cd33676d61fd9 100644 --- a/src/libcollections/bit.rs +++ b/src/libcollections/bit.rs @@ -1537,7 +1537,7 @@ pub fn shrink_to_fit(&mut self) { bit_vec.nbits = trunc_len * u32::BITS; } - /// Iterator over each u32 stored in the `BitSet`. + /// Iterator over each usize stored in the `BitSet`. /// /// # Examples /// @@ -1558,7 +1558,7 @@ pub fn iter(&self) -> bit_set::Iter { SetIter {set: self, next_idx: 0} } - /// Iterator over each u32 stored in `self` union `other`. + /// Iterator over each usize stored in `self` union `other`. /// See [union_with](#method.union_with) for an efficient in-place version. /// /// # Examples @@ -1658,7 +1658,7 @@ fn diff(w1: u32, w2: u32) -> u32 { w1 & !w2 } }) } - /// Iterator over each u32 stored in the symmetric difference of `self` and `other`. + /// Iterator over each usize stored in the symmetric difference of `self` and `other`. /// See [symmetric_difference_with](#method.symmetric_difference_with) for /// an efficient in-place version. /// diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index aaf615ee404095c07d84aae94d46fecd6299b65a..0f1e55544e1af5f5a02a158c2cbda5aa36ac6f4d 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -745,6 +745,7 @@ fn baz() { For example: +``` let x: i32 = "I am not a number!"; // ~~~ ~~~~~~~~~~~~~~~~~~~~ // | | @@ -752,6 +753,7 @@ fn baz() { // | compiler infers type `&str` // | // type `i32` assigned to variable `x` +``` "##, E0309: r##" @@ -760,6 +762,7 @@ fn baz() { must be as long as the data needs to be alive, and missing the constraint that denotes this will cause this error. +``` // This won't compile because T is not constrained, meaning the data // stored in it is not guaranteed to last as long as the reference struct Foo<'a, T> { @@ -770,6 +773,7 @@ struct Foo<'a, T> { struct Foo<'a, T: 'a> { foo: &'a T } +``` "##, E0310: r##" @@ -778,6 +782,7 @@ struct Foo<'a, T: 'a> { must be as long as the data needs to be alive, and missing the constraint that denotes this will cause this error. +``` // This won't compile because T is not constrained to the static lifetime // the reference needs struct Foo { @@ -788,6 +793,7 @@ struct Foo { struct Foo { foo: &'static T } +``` "## } diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs index 677254238c03498143cda5e658a8c1c22bb45b98..54ec1aace92112fe16a1109126004b15fdbacdc6 100644 --- a/src/librustc_typeck/astconv.rs +++ b/src/librustc_typeck/astconv.rs @@ -1603,7 +1603,8 @@ pub fn ast_ty_to_ty<'tcx>(this: &AstConv<'tcx>, Some(i as usize)), _ => { span_err!(tcx.sess, ast_ty.span, E0249, - "expected constant expr for array length"); + "expected constant integer expression \ + for array length"); this.tcx().types.err } } diff --git a/src/librustc_typeck/diagnostics.rs b/src/librustc_typeck/diagnostics.rs index 026ba3d08b42bea90bc74aac4fa37e6c910861ac..ea872d1014425e9b6f0e31deef6f8d8a16d7f35d 100644 --- a/src/librustc_typeck/diagnostics.rs +++ b/src/librustc_typeck/diagnostics.rs @@ -150,6 +150,148 @@ enum Empty {} ``` fn(isize, *const *const u8) -> isize ``` +"##, + +E0184: r##" +Explicitly implementing both Drop and Copy for a type is currently disallowed. +This feature can make some sense in theory, but the current implementation is +incorrect and can lead to memory unsafety (see [issue #20126][iss20126]), so +it has been disabled for now. + +[iss20126]: https://github.com/rust-lang/rust/issues/20126 +"##, + +E0204: r##" +An attempt to implement the `Copy` trait for a struct failed because one of the +fields does not implement `Copy`. To fix this, you must implement `Copy` for the +mentioned field. Note that this may not be possible, as in the example of + +``` +struct Foo { + foo : Vec, +} + +impl Copy for Foo { } +``` + +This fails because `Vec` does not implement `Copy` for any `T`. + +Here's another example that will fail: + +``` +#[derive(Copy)] +struct Foo<'a> { + ty: &'a mut bool, +} +``` + +This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this +differs from the behavior for `&T`, which is `Copy` when `T` is `Copy`). +"##, + +E0205: r##" +An attempt to implement the `Copy` trait for an enum failed because one of the +variants does not implement `Copy`. To fix this, you must implement `Copy` for +the mentioned variant. Note that this may not be possible, as in the example of + +``` +enum Foo { + Bar(Vec), + Baz, +} + +impl Copy for Foo { } +``` + +This fails because `Vec` does not implement `Copy` for any `T`. + +Here's another example that will fail: + +``` +#[derive(Copy)] +enum Foo<'a> { + Bar(&'a mut bool), + Baz +} +``` + +This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this +differs from the behavior for `&T`, which is `Copy` when `T` is `Copy`). +"##, + +E0206: r##" +You can only implement `Copy` for a struct or enum. Both of the following +examples will fail, because neither `i32` (primitive type) nor `&'static Bar` +(reference to `Bar`) is a struct or enum: + +``` +type Foo = i32; +impl Copy for Foo { } // error + +#[derive(Copy, Clone)] +struct Bar; +impl Copy for &'static Bar { } // error +``` +"##, + +E0243: r##" +This error indicates that not enough type parameters were found in a type or +trait. + +For example, the `Foo` struct below is defined to be generic in `T`, but the +type parameter is missing in the definition of `Bar`: + +``` +struct Foo { x: T } + +struct Bar { x: Foo } +``` +"##, + +E0244: r##" +This error indicates that too many type parameters were found in a type or +trait. + +For example, the `Foo` struct below has no type parameters, but is supplied +with two in the definition of `Bar`: + +``` +struct Foo { x: bool } + +struct Bar { x: Foo } +``` +"##, + +E0249: r##" +This error indicates a constant expression for the array length was found, but +it was not an integer (signed or unsigned) expression. + +Some examples of code that produces this error are: + +``` +const A: [u32; "hello"] = []; // error +const B: [u32; true] = []; // error +const C: [u32; 0.0] = []; // error +"##, + +E0250: r##" +This means there was an error while evaluating the expression for the length of +a fixed-size array type. + +Some examples of code that produces this error are: + +``` +// divide by zero in the length expression +const A: [u32; 1/0] = []; + +// Rust currently will not evaluate the function `foo` at compile time +fn foo() -> usize { 12 } +const B: [u32; foo()] = []; + +// it is an error to try to add `u8` and `f64` +use std::{f64, u8}; +const C: [u32; u8::MAX + f64::EPSILON] = []; +``` "## } @@ -164,18 +306,18 @@ enum Empty {} E0030, E0031, E0033, - E0034, - E0035, - E0036, - E0038, + E0034, // multiple applicable methods in scope + E0035, // does not take type parameters + E0036, // incorrect number of type parameters given for this method + E0038, // cannot convert to a trait object because trait is not object-safe E0040, // explicit use of destructor method - E0044, - E0045, + E0044, // foreign items may not have type parameters + E0045, // variadic function must have C calling convention E0049, E0050, E0053, - E0055, - E0057, + E0055, // method has an incompatible type for trait + E0057, // method has an incompatible type for trait E0059, E0060, E0061, @@ -232,7 +374,6 @@ enum Empty {} E0178, E0182, E0183, - E0184, E0185, E0186, E0187, // can't infer the kind of the closure @@ -254,12 +395,6 @@ enum Empty {} E0202, // associated items are not allowed in inherent impls E0203, // type parameter has more than one relaxed default bound, // and only one is supported - E0204, // trait `Copy` may not be implemented for this type; field - // does not implement `Copy` - E0205, // trait `Copy` may not be implemented for this type; variant - // does not implement `copy` - E0206, // trait `Copy` may not be implemented for this type; type is - // not a structure or enumeration E0207, // type parameter is not constrained by the impl trait, self type, or predicate E0208, E0209, // builtin traits can only be implemented on structs or enums @@ -296,14 +431,10 @@ enum Empty {} E0240, E0241, E0242, // internal error looking up a definition - E0243, // wrong number of type arguments - E0244, // wrong number of type arguments E0245, // not a trait E0246, // illegal recursive type E0247, // found module name used as a type E0248, // found value name used as a type - E0249, // expected constant expr for array length - E0250, // expected constant expr for array length E0318, // can't create default impls for traits outside their crates E0319, // trait impls for defaulted traits allowed just for structs/enums E0320, // recursive overflow during dropck diff --git a/src/libstd/path.rs b/src/libstd/path.rs index 21f873e687743ed7918202f9b3f10e3ecb12d6b9..934b3156357d64e09a2ea574c78c6be9027ff9d4 100644 --- a/src/libstd/path.rs +++ b/src/libstd/path.rs @@ -1199,7 +1199,7 @@ fn into(self) -> OsString { /// absolute, and so on. More details about the overall approach can be found in /// the module documentation. /// -/// This is an *unsized* type, meaning that it must always be used with behind a +/// This is an *unsized* type, meaning that it must always be used behind a /// pointer like `&` or `Box`. /// /// # Examples