diff options
author | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
---|---|---|
committer | Daniel Baumann <daniel.baumann@progress-linux.org> | 2024-05-30 03:57:31 +0000 |
commit | dc0db358abe19481e475e10c32149b53370f1a1c (patch) | |
tree | ab8ce99c4b255ce46f99ef402c27916055b899ee /src/doc | |
parent | Releasing progress-linux version 1.71.1+dfsg1-2~progress7.99u1. (diff) | |
download | rustc-dc0db358abe19481e475e10c32149b53370f1a1c.tar.xz rustc-dc0db358abe19481e475e10c32149b53370f1a1c.zip |
Merging upstream version 1.72.1+dfsg1.
Signed-off-by: Daniel Baumann <daniel.baumann@progress-linux.org>
Diffstat (limited to 'src/doc')
61 files changed, 1176 insertions, 706 deletions
diff --git a/src/doc/book/src/ch19-05-advanced-functions-and-closures.md b/src/doc/book/src/ch19-05-advanced-functions-and-closures.md index 69624f056..88c46847d 100644 --- a/src/doc/book/src/ch19-05-advanced-functions-and-closures.md +++ b/src/doc/book/src/ch19-05-advanced-functions-and-closures.md @@ -17,7 +17,7 @@ The syntax for specifying that a parameter is a function pointer is similar to that of closures, as shown in Listing 19-27, where we’ve defined a function `add_one` that adds one to its parameter. The function `do_twice` takes two parameters: a function pointer to any function that takes an `i32` parameter -and returns an `i32`, and one `i32 value`. The `do_twice` function calls the +and returns an `i32`, and one `i32` value. The `do_twice` function calls the function `f` twice, passing it the `arg` value, then adds the two function call results together. The `main` function calls `do_twice` with the arguments `add_one` and `5`. diff --git a/src/doc/nomicon/src/phantom-data.md b/src/doc/nomicon/src/phantom-data.md index ca1c2c21c..449d9e774 100644 --- a/src/doc/nomicon/src/phantom-data.md +++ b/src/doc/nomicon/src/phantom-data.md @@ -24,7 +24,7 @@ We do this using `PhantomData`, which is a special marker type. `PhantomData` consumes no space, but simulates a field of the given type for the purpose of static analysis. This was deemed to be less error-prone than explicitly telling the type-system the kind of variance that you want, while also providing other -useful things such as the information needed by drop check. +useful things such as auto traits and the information needed by drop check. Iter logically contains a bunch of `&'a T`s, so this is exactly what we tell the `PhantomData` to simulate: @@ -234,14 +234,14 @@ standard library made a utility for itself called `Unique<T>` which: Here’s a table of all the wonderful ways `PhantomData` could be used: -| Phantom type | `'a` | `T` | -|-----------------------------|-----------|---------------------------| -| `PhantomData<T>` | - | covariant (with drop check) | -| `PhantomData<&'a T>` | covariant | covariant | -| `PhantomData<&'a mut T>` | covariant | invariant | -| `PhantomData<*const T>` | - | covariant | -| `PhantomData<*mut T>` | - | invariant | -| `PhantomData<fn(T)>` | - | contravariant | -| `PhantomData<fn() -> T>` | - | covariant | -| `PhantomData<fn(T) -> T>` | - | invariant | -| `PhantomData<Cell<&'a ()>>` | invariant | - | +| Phantom type | `'a` | `T` | `Send` | `Sync` | +|-----------------------------|-----------|-----------------------------|-----------|-----------| +| `PhantomData<T>` | - | covariant (with drop check) | `T: Send` | `T: Sync` | +| `PhantomData<&'a T>` | covariant | covariant | `T: Sync` | `T: Sync` | +| `PhantomData<&'a mut T>` | covariant | invariant | `T: Send` | `T: Sync` | +| `PhantomData<*const T>` | - | covariant | - | - | +| `PhantomData<*mut T>` | - | invariant | - | - | +| `PhantomData<fn(T)>` | - | contravariant | `Send` | `Sync` | +| `PhantomData<fn() -> T>` | - | covariant | `Send` | `Sync` | +| `PhantomData<fn(T) -> T>` | - | invariant | `Send` | `Sync` | +| `PhantomData<Cell<&'a ()>>` | invariant | - | `Send` | - | diff --git a/src/doc/nomicon/src/subtyping.md b/src/doc/nomicon/src/subtyping.md index 79b29beb0..f63b532cc 100644 --- a/src/doc/nomicon/src/subtyping.md +++ b/src/doc/nomicon/src/subtyping.md @@ -1,189 +1,166 @@ # Subtyping and Variance -Subtyping is a relationship between types that allows statically typed -languages to be a bit more flexible and permissive. +Rust uses lifetimes to track the relationships between borrows and ownership. +However, a naive implementation of lifetimes would be either too restrictive, +or permit undefined behavior. -Subtyping in Rust is a bit different from subtyping in other languages. This -makes it harder to give simple examples, which is a problem since subtyping, -and especially variance, is already hard to understand properly. As in, -even compiler writers mess it up all the time. +In order to allow flexible usage of lifetimes +while also preventing their misuse, Rust uses **subtyping** and **variance**. -To keep things simple, this section will consider a small extension to the -Rust language that adds a new and simpler subtyping relationship. After -establishing concepts and issues under this simpler system, -we will then relate it back to how subtyping actually occurs in Rust. - -So here's our simple extension, *Objective Rust*, featuring three new types: +Let's start with an example. ```rust -trait Animal { - fn snuggle(&self); - fn eat(&mut self); -} - -trait Cat: Animal { - fn meow(&self); +// Note: debug expects two parameters with the *same* lifetime +fn debug<'a>(a: &'a str, b: &'a str) { + println!("a = {a:?} b = {b:?}"); } -trait Dog: Animal { - fn bark(&self); +fn main() { + let hello: &'static str = "hello"; + { + let world = String::from("world"); + let world = &world; // 'world has a shorter lifetime than 'static + debug(hello, world); + } } ``` -But unlike normal traits, we can use them as concrete and sized types, just like structs. - -Now, say we have a very simple function that takes an Animal, like this: +In a conservative implementation of lifetimes, since `hello` and `world` have different lifetimes, +we might see the following error: -<!-- ignore: simplified code --> -```rust,ignore -fn love(pet: Animal) { - pet.snuggle(); -} +```text +error[E0308]: mismatched types + --> src/main.rs:10:16 + | +10 | debug(hello, world); + | ^ + | | + | expected `&'static str`, found struct `&'world str` ``` -By default, static types must match *exactly* for a program to compile. As such, -this code won't compile: +This would be rather unfortunate. In this case, +what we want is to accept any type that lives *at least as long* as `'world`. +Let's try using subtyping with our lifetimes. -<!-- ignore: simplified code --> -```rust,ignore -let mr_snuggles: Cat = ...; -love(mr_snuggles); // ERROR: expected Animal, found Cat -``` +## Subtyping -Mr. Snuggles is a Cat, and Cats aren't *exactly* Animals, so we can't love him! 😿 +Subtyping is the idea that one type can be used in place of another. -This is annoying because Cats *are* Animals. They support every operation -an Animal supports, so intuitively `love` shouldn't care if we pass it a `Cat`. -We should be able to just **forget** the non-animal parts of our `Cat`, as they -aren't necessary to love it. +Let's define that `Sub` is a subtype of `Super` (we'll be using the notation `Sub <: Super` throughout this chapter). -This is exactly the problem that *subtyping* is intended to fix. Because Cats are just -Animals **and more**, we say Cat is a *subtype* of Animal (because Cats are a *subset* -of all the Animals). Equivalently, we say that Animal is a *supertype* of Cat. -With subtypes, we can tweak our overly strict static type system -with a simple rule: anywhere a value of type `T` is expected, we will also -accept values that are subtypes of `T`. +What this is suggesting to us is that the set of *requirements* that `Super` defines +are completely satisfied by `Sub`. `Sub` may then have more requirements. -Or more concretely: anywhere an Animal is expected, a Cat or Dog will also work. +Now, in order to use subtyping with lifetimes, we need to define the requirement of a lifetime: -As we will see throughout the rest of this section, subtyping is a lot more complicated -and subtle than this, but this simple rule is a very good 99% intuition. And unless you -write unsafe code, the compiler will automatically handle all the corner cases for you. +> `'a` defines a region of code. -But this is the Rustonomicon. We're writing unsafe code, so we need to understand how -this stuff really works, and how we can mess it up. +Now that we have a defined set of requirements for lifetimes, we can define how they relate to each other: -The core problem is that this rule, naively applied, will lead to *meowing Dogs*. That is, -we can convince someone that a Dog is actually a Cat. This completely destroys the fabric -of our static type system, making it worse than useless (and leading to Undefined Behavior). +> `'long <: 'short` if and only if `'long` defines a region of code that **completely contains** `'short`. -Here's a simple example of this happening when we apply subtyping in a completely naive -"find and replace" way. +`'long` may define a region larger than `'short`, but that still fits our definition. -<!-- ignore: simplified code --> -```rust,ignore -fn evil_feeder(pet: &mut Animal) { - let spike: Dog = ...; +> As we will see throughout the rest of this chapter, +subtyping is a lot more complicated and subtle than this, +but this simple rule is a very good 99% intuition. +And unless you write unsafe code, the compiler will automatically handle all the corner cases for you. + +> But this is the Rustonomicon. We're writing unsafe code, +so we need to understand how this stuff really works, and how we can mess it up. - // `pet` is an Animal, and Dog is a subtype of Animal, - // so this should be fine, right..? - *pet = spike; +Going back to our example above, we can say that `'static <: 'world`. +For now, let's also accept the idea that subtypes of lifetimes can be passed through references +(more on this in [Variance](#variance)), +_e.g._ `&'static str` is a subtype of `&'world str`, then we can "downgrade" `&'static str` into a `&'world str`. +With that, the example above will compile: + +```rust +fn debug<'a>(a: &'a str, b: &'a str) { + println!("a = {a:?} b = {b:?}"); } fn main() { - let mut mr_snuggles: Cat = ...; - evil_feeder(&mut mr_snuggles); // Replaces mr_snuggles with a Dog - mr_snuggles.meow(); // OH NO, MEOWING DOG! + let hello: &'static str = "hello"; + { + let world = String::from("world"); + let world = &world; // 'world has a shorter lifetime than 'static + debug(hello, world); // hello silently downgrades from `&'static str` into `&'world str` + } } ``` -Clearly, we need a more robust system than "find and replace". That system is *variance*, -which is a set of rules governing how subtyping should compose. Most importantly, variance -defines situations where subtyping should be disabled. - -But before we get into variance, let's take a quick peek at where subtyping actually occurs in -Rust: *lifetimes*! - -> NOTE: The typed-ness of lifetimes is a fairly arbitrary construct that some -> disagree with. However it simplifies our analysis to treat lifetimes -> and types uniformly. +## Variance -Lifetimes are just regions of code, and regions can be partially ordered with the *contains* -(outlives) relationship. Subtyping on lifetimes is in terms of that relationship: -if `'big: 'small` ("big contains small" or "big outlives small"), then `'big` is a subtype -of `'small`. This is a large source of confusion, because it seems backwards -to many: the bigger region is a *subtype* of the smaller region. But it makes -sense if you consider our Animal example: Cat is an Animal *and more*, -just as `'big` is `'small` *and more*. +Above, we glossed over the fact that `'static <: 'b` implied that `&'static T <: &'b T`. This uses a property known as _variance_. +It's not always as simple as this example, though. To understand that, let's try to extend this example a bit: -Put another way, if someone wants a reference that lives for `'small`, -usually what they actually mean is that they want a reference that lives -for *at least* `'small`. They don't actually care if the lifetimes match -exactly. So it should be ok for us to **forget** that something lives for -`'big` and only remember that it lives for `'small`. +```rust,compile_fail,E0597 +fn assign<T>(input: &mut T, val: T) { + *input = val; +} -The meowing dog problem for lifetimes will result in us being able to -store a short-lived reference in a place that expects a longer-lived one, -creating a dangling reference and letting us use-after-free. +fn main() { + let mut hello: &'static str = "hello"; + { + let world = String::from("world"); + assign(&mut hello, &world); + } + println!("{hello}"); // use after free 😿 +} +``` -It will be useful to note that `'static`, the forever lifetime, is a subtype of -every lifetime because by definition it outlives everything. We will be using -this relationship in later examples to keep them as simple as possible. +In `assign`, we are setting the `hello` reference to point to `world`. +But then `world` goes out of scope, before the later use of `hello` in the println! -With all that said, we still have no idea how to actually *use* subtyping of lifetimes, -because nothing ever has type `'a`. Lifetimes only occur as part of some larger type -like `&'a u32` or `IterMut<'a, u32>`. To apply lifetime subtyping, we need to know -how to compose subtyping. Once again, we need *variance*. +This is a classic use-after-free bug! -## Variance +Our first instinct might be to blame the `assign` impl, but there's really nothing wrong here. +It shouldn't be surprising that we might want to assign a `T` into a `T`. -Variance is where things get a bit complicated. +The problem is that we cannot assume that `&mut &'static str` and `&mut &'b str` are compatible. +This means that `&mut &'static str` **cannot** be a *subtype* of `&mut &'b str`, +even if `'static` is a subtype of `'b`. -Variance is a property that *type constructors* have with respect to their -arguments. A type constructor in Rust is any generic type with unbound arguments. -For instance `Vec` is a type constructor that takes a type `T` and returns -`Vec<T>`. `&` and `&mut` are type constructors that take two inputs: a -lifetime, and a type to point to. +Variance is the concept that Rust borrows to define relationships about subtypes through their generic parameters. -> NOTE: For convenience we will often refer to `F<T>` as a type constructor just so +> NOTE: For convenience we will define a generic type `F<T>` so > that we can easily talk about `T`. Hopefully this is clear in context. -A type constructor F's *variance* is how the subtyping of its inputs affects the +The type `F`'s *variance* is how the subtyping of its inputs affects the subtyping of its outputs. There are three kinds of variance in Rust. Given two types `Sub` and `Super`, where `Sub` is a subtype of `Super`: -* `F` is *covariant* if `F<Sub>` is a subtype of `F<Super>` (subtyping "passes through") -* `F` is *contravariant* if `F<Super>` is a subtype of `F<Sub>` (subtyping is "inverted") -* `F` is *invariant* otherwise (no subtyping relationship exists) +* `F` is **covariant** if `F<Sub>` is a subtype of `F<Super>` (the subtype property is passed through) +* `F` is **contravariant** if `F<Super>` is a subtype of `F<Sub>` (the subtype property is "inverted") +* `F` is **invariant** otherwise (no subtyping relationship exists) -If `F` has multiple type parameters, we can talk about the individual variances -by saying that, for example, `F<T, U>` is covariant over `T` and invariant over `U`. +If we remember from the above examples, +it was ok for us to treat `&'a T` as a subtype of `&'b T` if `'a <: 'b`, +therefore we can say that `&'a T` is *covariant* over `'a`. -It is very useful to keep in mind that covariance is, in practical terms, "the" -variance. Almost all consideration of variance is in terms of whether something -should be covariant or invariant. Actually witnessing contravariance is quite difficult -in Rust, though it does in fact exist. +Also, we saw that it was not ok for us to treat `&mut &'a U` as a subtype of `&mut &'b U`, +therefore we can say that `&mut T` is *invariant* over `T` -Here is a table of important variances which the rest of this section will be devoted -to trying to explain: +Here is a table of some other generic types and their variances: -| | | 'a | T | U | -|---|-----------------|:---------:|:-----------------:|:---------:| -| * | `&'a T ` | covariant | covariant | | -| * | `&'a mut T` | covariant | invariant | | -| * | `Box<T>` | | covariant | | -| | `Vec<T>` | | covariant | | -| * | `UnsafeCell<T>` | | invariant | | -| | `Cell<T>` | | invariant | | -| * | `fn(T) -> U` | | **contra**variant | covariant | -| | `*const T` | | covariant | | -| | `*mut T` | | invariant | | +| | 'a | T | U | +|-----------------|:---------:|:-----------------:|:---------:| +| `&'a T ` | covariant | covariant | | +| `&'a mut T` | covariant | invariant | | +| `Box<T>` | | covariant | | +| `Vec<T>` | | covariant | | +| `UnsafeCell<T>` | | invariant | | +| `Cell<T>` | | invariant | | +| `fn(T) -> U` | | **contra**variant | covariant | +| `*const T` | | covariant | | +| `*mut T` | | invariant | | -The types with \*'s are the ones we will be focusing on, as they are in -some sense "fundamental". All the others can be understood by analogy to the others: +Some of these can be explained simply in relation to the others: * `Vec<T>` and all other owning pointers and collections follow the same logic as `Box<T>` * `Cell<T>` and all other interior mutability types follow the same logic as `UnsafeCell<T>` +* `UnsafeCell<T>` having interior mutability gives it the same variance properties as `&mut T` * `*const T` follows the logic of `&T` * `*mut T` follows the logic of `&mut T` (or `UnsafeCell<T>`) @@ -197,116 +174,45 @@ For more types, see the ["Variance" section][variance-table] on the reference. > take references with specific lifetimes (as opposed to the usual "any lifetime", > which gets into higher rank lifetimes, which work independently of subtyping). -Ok, that's enough type theory! Let's try to apply the concept of variance to Rust -and look at some examples. - -First off, let's revisit the meowing dog example: - -<!-- ignore: simplified code --> -```rust,ignore -fn evil_feeder(pet: &mut Animal) { - let spike: Dog = ...; - - // `pet` is an Animal, and Dog is a subtype of Animal, - // so this should be fine, right..? - *pet = spike; -} +Now that we have some more formal understanding of variance, +let's go through some more examples in more detail. -fn main() { - let mut mr_snuggles: Cat = ...; - evil_feeder(&mut mr_snuggles); // Replaces mr_snuggles with a Dog - mr_snuggles.meow(); // OH NO, MEOWING DOG! -} -``` - -If we look at our table of variances, we see that `&mut T` is *invariant* over `T`. -As it turns out, this completely fixes the issue! With invariance, the fact that -Cat is a subtype of Animal doesn't matter; `&mut Cat` still won't be a subtype of -`&mut Animal`. The static type checker will then correctly stop us from passing -a Cat into `evil_feeder`. - -The soundness of subtyping is based on the idea that it's ok to forget unnecessary -details. But with references, there's always someone that remembers those details: -the value being referenced. That value expects those details to keep being true, -and may behave incorrectly if its expectations are violated. - -The problem with making `&mut T` covariant over `T` is that it gives us the power -to modify the original value *when we don't remember all of its constraints*. -And so, we can make someone have a Dog when they're certain they still have a Cat. - -With that established, we can easily see why `&T` being covariant over `T` *is* -sound: it doesn't let you modify the value, only look at it. Without any way to -mutate, there's no way for us to mess with any details. We can also see why -`UnsafeCell` and all the other interior mutability types must be invariant: they -make `&T` work like `&mut T`! - -Now what about the lifetime on references? Why is it ok for both kinds of references -to be covariant over their lifetimes? Well, here's a two-pronged argument: - -First and foremost, subtyping references based on their lifetimes is *the entire point -of subtyping in Rust*. The only reason we have subtyping is so we can pass -long-lived things where short-lived things are expected. So it better work! - -Second, and more seriously, lifetimes are only a part of the reference itself. The -type of the referent is shared knowledge, which is why adjusting that type in only -one place (the reference) can lead to issues. But if you shrink down a reference's -lifetime when you hand it to someone, that lifetime information isn't shared in -any way. There are now two independent references with independent lifetimes. -There's no way to mess with the original reference's lifetime using the other one. - -Or rather, the only way to mess with someone's lifetime is to build a meowing dog. -But as soon as you try to build a meowing dog, the lifetime should be wrapped up -in an invariant type, preventing the lifetime from being shrunk. To understand this -better, let's port the meowing dog problem over to real Rust. - -In the meowing dog problem we take a subtype (Cat), convert it into a supertype -(Animal), and then use that fact to overwrite the subtype with a value that satisfies -the constraints of the supertype but not the subtype (Dog). - -So with lifetimes, we want to take a long-lived thing, convert it into a -short-lived thing, and then use that to write something that doesn't live long -enough into the place expecting something long-lived. - -Here it is: - -```rust,compile_fail -fn evil_feeder<T>(input: &mut T, val: T) { +```rust,compile_fail,E0597 +fn assign<T>(input: &mut T, val: T) { *input = val; } fn main() { - let mut mr_snuggles: &'static str = "meow! :3"; // mr. snuggles forever!! + let mut hello: &'static str = "hello"; { - let spike = String::from("bark! >:V"); - let spike_str: &str = &spike; // Only lives for the block - evil_feeder(&mut mr_snuggles, spike_str); // EVIL! + let world = String::from("world"); + assign(&mut hello, &world); } - println!("{}", mr_snuggles); // Use after free? + println!("{hello}"); } ``` And what do we get when we run this? ```text -error[E0597]: `spike` does not live long enough - --> src/main.rs:9:31 +error[E0597]: `world` does not live long enough + --> src/main.rs:9:28 | -6 | let mut mr_snuggles: &'static str = "meow! :3"; // mr. snuggles forever!! - | ------------ type annotation requires that `spike` is borrowed for `'static` +6 | let mut hello: &'static str = "hello"; + | ------------ type annotation requires that `world` is borrowed for `'static` ... -9 | let spike_str: &str = &spike; // Only lives for the block - | ^^^^^^ borrowed value does not live long enough -10 | evil_feeder(&mut mr_snuggles, spike_str); // EVIL! -11 | } - | - `spike` dropped here while still borrowed +9 | assign(&mut hello, &world); + | ^^^^^^ borrowed value does not live long enough +10 | } + | - `world` dropped here while still borrowed ``` Good, it doesn't compile! Let's break down what's happening here in detail. -First let's look at the new `evil_feeder` function: +First let's look at the `assign` function: ```rust -fn evil_feeder<T>(input: &mut T, val: T) { +fn assign<T>(input: &mut T, val: T) { *input = val; } ``` @@ -315,60 +221,43 @@ All it does is take a mutable reference and a value and overwrite the referent w What's important about this function is that it creates a type equality constraint. It clearly says in its signature the referent and the value must be the *exact same* type. -Meanwhile, in the caller we pass in `&mut &'static str` and `&'spike_str str`. +Meanwhile, in the caller we pass in `&mut &'static str` and `&'world str`. Because `&mut T` is invariant over `T`, the compiler concludes it can't apply any subtyping to the first argument, and so `T` must be exactly `&'static str`. -The other argument is only an `&'a str`, which *is* covariant over `'a`. So the compiler -adopts a constraint: `&'spike_str str` must be a subtype of `&'static str` (inclusive), -which in turn implies `'spike_str` must be a subtype of `'static` (inclusive). Which is to say, -`'spike_str` must contain `'static`. But only one thing contains `'static` -- `'static` itself! +This is counter to the `&T` case: -This is why we get an error when we try to assign `&spike` to `spike_str`. The -compiler has worked backwards to conclude `spike_str` must live forever, and `&spike` -simply can't live that long. +```rust +fn debug<T: std::fmt::Debug>(a: T, b: T) { + println!("a = {a:?} b = {b:?}"); +} +``` -So even though references are covariant over their lifetimes, they "inherit" invariance -whenever they're put into a context that could do something bad with that. In this case, -we inherited invariance as soon as we put our reference inside an `&mut T`. +where similarly `a` and `b` must have the same type `T`. +But since `&'a T` *is* covariant over `'a`, we are allowed to perform subtyping. +So the compiler decides that `&'static str` can become `&'b str` if and only if +`&'static str` is a subtype of `&'b str`, which will hold if `'static <: 'b`. +This is true, so the compiler is happy to continue compiling this code. -As it turns out, the argument for why it's ok for Box (and Vec, Hashmap, etc.) to -be covariant is pretty similar to the argument for why it's ok for -references to be covariant: as soon as you try to stuff them in something like a -mutable reference, they inherit invariance and you're prevented from doing anything -bad. +As it turns out, the argument for why it's ok for Box (and Vec, HashMap, etc.) to be covariant is pretty similar to the argument for why it's ok for lifetimes to be covariant: as soon as you try to stuff them in something like a mutable reference, they inherit invariance and you're prevented from doing anything bad. -However, Box makes it easier to focus on the by-value aspect of references that we -partially glossed over. +However Box makes it easier to focus on the by-value aspect of references that we partially glossed over. -Unlike a lot of languages which allow values to be freely aliased at all times, -Rust has a very strict rule: if you're allowed to mutate or move a value, you -are guaranteed to be the only one with access to it. +Unlike a lot of languages which allow values to be freely aliased at all times, Rust has a very strict rule: if you're allowed to mutate or move a value, you are guaranteed to be the only one with access to it. Consider the following code: -<!-- ignore: simplified code --> ```rust,ignore -let mr_snuggles: Box<Cat> = ..; -let spike: Box<Dog> = ..; +let hello: Box<&'static str> = Box::new("hello"); -let mut pet: Box<Animal>; -pet = mr_snuggles; -pet = spike; +let mut world: Box<&'b str>; +world = hello; ``` -There is no problem at all with the fact that we have forgotten that `mr_snuggles` was a Cat, -or that we overwrote him with a Dog, because as soon as we moved mr_snuggles to a variable -that only knew he was an Animal, **we destroyed the only thing in the universe that -remembered he was a Cat**! - -In contrast to the argument about immutable references being soundly covariant because they -don't let you change anything, owned values can be covariant because they make you -change *everything*. There is no connection between old locations and new locations. -Applying by-value subtyping is an irreversible act of knowledge destruction, and -without any memory of how things used to be, no one can be tricked into acting on -that old information! +There is no problem at all with the fact that we have forgotten that `hello` was alive for `'static`, +because as soon as we moved `hello` to a variable that only knew it was alive for `'b`, +**we destroyed the only thing in the universe that remembered it lived for longer**! Only one thing left to explain: function pointers. @@ -376,43 +265,78 @@ To see why `fn(T) -> U` should be covariant over `U`, consider the following sig <!-- ignore: simplified code --> ```rust,ignore -fn get_animal() -> Animal; +fn get_str() -> &'a str; ``` -This function claims to produce an Animal. As such, it is perfectly valid to +This function claims to produce a `str` bound by some liftime `'a`. As such, it is perfectly valid to provide a function with the following signature instead: <!-- ignore: simplified code --> ```rust,ignore -fn get_animal() -> Cat; +fn get_static() -> &'static str; ``` -After all, Cats are Animals, so always producing a Cat is a perfectly valid way -to produce Animals. Or to relate it back to real Rust: if we need a function -that is supposed to produce something that lives for `'short`, it's perfectly -fine for it to produce something that lives for `'long`. We don't care, we can -just forget that fact. +So when the function is called, all it's expecting is a `&str` which lives at least the lifetime of `'a`, +it doesn't matter if the value actually lives longer. However, the same logic does not apply to *arguments*. Consider trying to satisfy: <!-- ignore: simplified code --> ```rust,ignore -fn handle_animal(Animal); +fn store_ref(&'a str); ``` with: <!-- ignore: simplified code --> ```rust,ignore -fn handle_animal(Cat); +fn store_static(&'static str); ``` -The first function can accept Dogs, but the second function absolutely can't. +The first function can accept any string reference as long as it lives at least for `'a`, +but the second cannot accept a string reference that lives for any duration less than `'static`, +which would cause a conflict. Covariance doesn't work here. But if we flip it around, it actually *does* -work! If we need a function that can handle Cats, a function that can handle *any* -Animal will surely work fine. Or to relate it back to real Rust: if we need a -function that can handle anything that lives for at least `'long`, it's perfectly -fine for it to be able to handle anything that lives for at least `'short`. +work! If we need a function that can handle `&'static str`, a function that can handle *any* reference lifetime +will surely work fine. + +Let's see this in practice + +```rust,compile_fail +# use std::cell::RefCell; +thread_local! { + pub static StaticVecs: RefCell<Vec<&'static str>> = RefCell::new(Vec::new()); +} + +/// saves the input given into a thread local `Vec<&'static str>` +fn store(input: &'static str) { + StaticVecs.with(|v| { + v.borrow_mut().push(input); + }) +} + +/// Calls the function with it's input (must have the same lifetime!) +fn demo<'a>(input: &'a str, f: fn(&'a str)) { + f(input); +} + +fn main() { + demo("hello", store); // "hello" is 'static. Can call `store` fine + + { + let smuggle = String::from("smuggle"); + + // `&smuggle` is not static. If we were to call `store` with `&smuggle`, + // we would have pushed an invalid lifetime into the `StaticVecs`. + // Therefore, `fn(&'static str)` cannot be a subtype of `fn(&'a str)` + demo(&smuggle, store); + } + + StaticVecs.with(|v| { + println!("{:?}", v.borrow()); // use after free 😿 + }); +} +``` And that's why function types, unlike anything else in the language, are **contra**variant over their arguments. diff --git a/src/doc/reference/src/comments.md b/src/doc/reference/src/comments.md index ad29c58e5..bf1e7caa1 100644 --- a/src/doc/reference/src/comments.md +++ b/src/doc/reference/src/comments.md @@ -42,7 +42,7 @@ Non-doc comments are interpreted as a form of whitespace. ## Doc comments Line doc comments beginning with exactly _three_ slashes (`///`), and block -doc comments (`/** ... */`), both inner doc comments, are interpreted as a +doc comments (`/** ... */`), both outer doc comments, are interpreted as a special syntax for [`doc` attributes]. That is, they are equivalent to writing `#[doc="..."]` around the body of the comment, i.e., `/// Foo` turns into `#[doc="Foo"]` and `/** Bar */` turns into `#[doc="Bar"]`. diff --git a/src/doc/reference/src/conditional-compilation.md b/src/doc/reference/src/conditional-compilation.md index 97840e4f6..c3a36effe 100644 --- a/src/doc/reference/src/conditional-compilation.md +++ b/src/doc/reference/src/conditional-compilation.md @@ -254,6 +254,12 @@ It is written as `cfg`, `(`, a configuration predicate, and finally `)`. If the predicate is true, the thing is rewritten to not have the `cfg` attribute on it. If the predicate is false, the thing is removed from the source code. +When a crate-level `cfg` has a false predicate, the behavior is slightly +different: any crate attributes preceding the `cfg` are kept, and any crate +attributes following the `cfg` are removed. This allows `#![no_std]` and +`#![no_core]` crates to avoid linking `std`/`core` even if a `#![cfg(...)]` has +removed the entire crate. + Some examples on functions: ```rust diff --git a/src/doc/reference/src/expressions/call-expr.md b/src/doc/reference/src/expressions/call-expr.md index 577f3f432..7a01e92e1 100644 --- a/src/doc/reference/src/expressions/call-expr.md +++ b/src/doc/reference/src/expressions/call-expr.md @@ -48,7 +48,7 @@ trait Pretty { } trait Ugly { - fn print(&self); + fn print(&self); } struct Foo; diff --git a/src/doc/reference/src/inline-assembly.md b/src/doc/reference/src/inline-assembly.md index 6c23d592c..26f1acedc 100644 --- a/src/doc/reference/src/inline-assembly.md +++ b/src/doc/reference/src/inline-assembly.md @@ -11,6 +11,7 @@ Support for inline assembly is stable on the following architectures: - ARM - AArch64 - RISC-V +- LoongArch The compiler will emit an error if `asm!` is used on an unsupported target. @@ -185,6 +186,8 @@ Here is the list of currently supported register classes: | RISC-V | `reg` | `x1`, `x[5-7]`, `x[9-15]`, `x[16-31]` (non-RV32E) | `r` | | RISC-V | `freg` | `f[0-31]` | `f` | | RISC-V | `vreg` | `v[0-31]` | Only clobbers | +| LoongArch | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` | +| LoongArch | `freg` | `$f[0-31]` | `f` | > **Notes**: > - On x86 we treat `reg_byte` differently from `reg` because the compiler can allocate `al` and `ah` separately whereas `reg` reserves the whole register. @@ -223,6 +226,8 @@ The availability of supported types for a particular register class may depend o | RISC-V | `freg` | `f` | `f32` | | RISC-V | `freg` | `d` | `f64` | | RISC-V | `vreg` | N/A | Only clobbers | +| LoongArch64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` | +| LoongArch64 | `freg` | None | `f32`, `f64` | > **Note**: For the purposes of the above table pointers, function pointers and `isize`/`usize` are treated as the equivalent integer type (`i16`/`i32`/`i64` depending on the target). @@ -284,15 +289,27 @@ Here is the list of all supported register aliases: | RISC-V | `f[10-17]` | `fa[0-7]` | | RISC-V | `f[18-27]` | `fs[2-11]` | | RISC-V | `f[28-31]` | `ft[8-11]` | +| LoongArch | `$r0` | `$zero` | +| LoongArch | `$r1` | `$ra` | +| LoongArch | `$r2` | `$tp` | +| LoongArch | `$r3` | `$sp` | +| LoongArch | `$r[4-11]` | `$a[0-7]` | +| LoongArch | `$r[12-20]` | `$t[0-8]` | +| LoongArch | `$r21` | | +| LoongArch | `$r22` | `$fp`, `$s9` | +| LoongArch | `$r[23-31]` | `$s[0-8]` | +| LoongArch | `$f[0-7]` | `$fa[0-7]` | +| LoongArch | `$f[8-23]` | `$ft[0-15]` | +| LoongArch | `$f[24-31]` | `$fs[0-7]` | Some registers cannot be used for input or output operands: | Architecture | Unsupported register | Reason | | ------------ | -------------------- | ------ | | All | `sp` | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V) | The frame pointer cannot be used as an input or output. | +| All | `bp` (x86), `x29` (AArch64), `x8` (RISC-V), `$fp` (LoongArch) | The frame pointer cannot be used as an input or output. | | ARM | `r7` or `r11` | On ARM the frame pointer can be either `r7` or `r11` depending on the target. The frame pointer cannot be used as an input or output. | -| All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `x9` (RISC-V) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | +| All | `si` (x86-32), `bx` (x86-64), `r6` (ARM), `x19` (AArch64), `x9` (RISC-V), `$s8` (LoongArch) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | x86 | `ip` | This is the program counter, not a real register. | | AArch64 | `xzr` | This is a constant zero register which can't be modified. | | AArch64 | `x18` | This is an OS-reserved register on some AArch64 targets. | @@ -300,6 +317,9 @@ Some registers cannot be used for input or output operands: | ARM | `r9` | This is an OS-reserved register on some ARM targets. | | RISC-V | `x0` | This is a constant zero register which can't be modified. | | RISC-V | `gp`, `tp` | These registers are reserved and cannot be used as inputs or outputs. | +| LoongArch | `$r0` or `$zero` | This is a constant zero register which can't be modified. | +| LoongArch | `$r2` or `$tp` | This is reserved for TLS. | +| LoongArch | `$r21` | This is reserved by the ABI. | The frame pointer and base pointer registers are reserved for internal use by LLVM. While `asm!` statements cannot explicitly specify the use of reserved registers, in some cases LLVM will allocate one of these reserved registers for `reg` operands. Assembly code making use of reserved registers should be careful since `reg` operands may use the same registers. @@ -346,6 +366,8 @@ The supported modifiers are a subset of LLVM's (and GCC's) [asm template argumen | ARM | `qreg` | `e` / `f` | `d0` / `d1` | `e` / `f` | | RISC-V | `reg` | None | `x1` | None | | RISC-V | `freg` | None | `f0` | None | +| LoongArch | `reg` | None | `$r1` | None | +| LoongArch | `freg` | None | `$f0` | None | > **Notes**: > - on ARM `e` / `f`: this prints the low or high doubleword register name of a NEON quad (128-bit) register. @@ -379,6 +401,7 @@ The following ABIs can be used with `clobber_abi`: | AArch64 | `"C"`, `"system"`, `"efiapi"` | `x[0-17]`, `x18`\*, `x30`, `v[0-31]`, `p[0-15]`, `ffr` | | ARM | `"C"`, `"system"`, `"efiapi"`, `"aapcs"` | `r[0-3]`, `r12`, `r14`, `s[0-15]`, `d[0-7]`, `d[16-31]` | | RISC-V | `"C"`, `"system"`, `"efiapi"` | `x1`, `x[5-7]`, `x[10-17]`, `x[28-31]`, `f[0-7]`, `f[10-17]`, `f[28-31]`, `v[0-31]` | +| LoongArch | `"C"`, `"system"`, `"efiapi"` | `$r1`, `$r[4-20]`, `$f[0-23]` | > Notes: > - On AArch64 `x18` only included in the clobber list if it is not considered as a reserved register on the target. @@ -466,6 +489,8 @@ To avoid undefined behavior, these rules must be followed when using function-sc - RISC-V - Floating-point exception flags in `fcsr` (`fflags`). - Vector extension state (`vtype`, `vl`, `vcsr`). + - LoongArch + - Floating-point condition flags in `$fcc[0-7]`. - On x86, the direction flag (DF in `EFLAGS`) is clear on entry to an asm block and must be clear on exit. - Behavior is undefined if the direction flag is set on exiting an asm block. - On x86, the x87 floating-point register stack must remain unchanged unless all of the `st([0-7])` registers have been marked as clobbered with `out("st(0)") _, out("st(1)") _, ...`. diff --git a/src/doc/reference/src/paths.md b/src/doc/reference/src/paths.md index cb6b24aa0..9efbda701 100644 --- a/src/doc/reference/src/paths.md +++ b/src/doc/reference/src/paths.md @@ -125,7 +125,7 @@ S::f(); // Calls the inherent impl. > `::`<sup>?</sup> _TypePathSegment_ (`::` _TypePathSegment_)<sup>\*</sup> > > _TypePathSegment_ :\ -> _PathIdentSegment_ `::`<sup>?</sup> ([_GenericArgs_] | _TypePathFn_)<sup>?</sup> +> _PathIdentSegment_ (`::`<sup>?</sup> ([_GenericArgs_] | _TypePathFn_))<sup>?</sup> > > _TypePathFn_ :\ > `(` _TypePathFnInputs_<sup>?</sup> `)` (`->` [_Type_])<sup>?</sup> diff --git a/src/doc/rust-by-example/CONTRIBUTING.md b/src/doc/rust-by-example/CONTRIBUTING.md index 665a708c0..43324d2bd 100644 --- a/src/doc/rust-by-example/CONTRIBUTING.md +++ b/src/doc/rust-by-example/CONTRIBUTING.md @@ -44,7 +44,7 @@ We use the following labels: ## Development workflow -To build RBE, [install Rust], and then: +To build RBE, [install Rust](https://www.rust-lang.org/tools/install), and then: ```bash $ git clone https://github.com/rust-lang/rust-by-example @@ -56,7 +56,7 @@ $ mdbook build [install Rust]: http://rust-lang.org/install.html The files will be in the `book` directory at the top-level; `mdbook serve` will -open the contents in your web browser. +open the contents in your web browser ([localhost:3000](http://localhost:3000) by default). To run the tests: diff --git a/src/doc/rust-by-example/src/conversion/from_into.md b/src/doc/rust-by-example/src/conversion/from_into.md index 47b327142..d927cdd78 100644 --- a/src/doc/rust-by-example/src/conversion/from_into.md +++ b/src/doc/rust-by-example/src/conversion/from_into.md @@ -51,16 +51,16 @@ convert into as the compiler is unable to determine this most of the time. However this is a small trade-off considering we get the functionality for free. ```rust,editable -use std::convert::From; +use std::convert::Into; #[derive(Debug)] struct Number { value: i32, } -impl From<i32> for Number { - fn from(item: i32) -> Self { - Number { value: item } +impl Into<Number> for i32 { + fn into(self) -> Number { + Number { value: self } } } diff --git a/src/doc/rust-by-example/src/conversion/string.md b/src/doc/rust-by-example/src/conversion/string.md index 9a17a2ce6..edadaaa51 100644 --- a/src/doc/rust-by-example/src/conversion/string.md +++ b/src/doc/rust-by-example/src/conversion/string.md @@ -28,7 +28,7 @@ fn main() { ## Parsing a String -One of the more common types to convert a string into is a number. The idiomatic +One of the more common types to convert a string into a number. The idiomatic approach to this is to use the [`parse`] function and either to arrange for type inference or to specify the type to parse using the 'turbofish' syntax. Both alternatives are shown in the following example. diff --git a/src/doc/rust-by-example/src/error/option_unwrap/and_then.md b/src/doc/rust-by-example/src/error/option_unwrap/and_then.md index 42a1f3ec0..78c094015 100644 --- a/src/doc/rust-by-example/src/error/option_unwrap/and_then.md +++ b/src/doc/rust-by-example/src/error/option_unwrap/and_then.md @@ -8,7 +8,7 @@ known in some languages as flatmap, comes in. `and_then()` calls its function input with the wrapped value and returns the result. If the `Option` is `None`, then it returns `None` instead. -In the following example, `cookable_v2()` results in an `Option<Food>`. +In the following example, `cookable_v3()` results in an `Option<Food>`. Using `map()` instead of `and_then()` would have given an `Option<Option<Food>>`, which is an invalid type for `eat()`. @@ -44,12 +44,18 @@ fn cookable_v1(food: Food) -> Option<Food> { } // This can conveniently be rewritten more compactly with `and_then()`: -fn cookable_v2(food: Food) -> Option<Food> { +fn cookable_v3(food: Food) -> Option<Food> { have_recipe(food).and_then(have_ingredients) } +// Otherwise we'd need to `flatten()` an `Option<Option<Food>>` +// to get an `Option<Food>`: +fn cookable_v2(food: Food) -> Option<Food> { + have_recipe(food).map(have_ingredients).flatten() +} + fn eat(food: Food, day: Day) { - match cookable_v2(food) { + match cookable_v3(food) { Some(food) => println!("Yay! On {:?} we get to eat {:?}.", day, food), None => println!("Oh no. We don't get to eat on {:?}?", day), } @@ -66,8 +72,9 @@ fn main() { ### See also: -[closures][closures], [`Option`][option], and [`Option::and_then()`][and_then] +[closures][closures], [`Option`][option], [`Option::and_then()`][and_then], and [`Option::flatten()`][flatten] [closures]: ../../fn/closures.md [option]: https://doc.rust-lang.org/std/option/enum.Option.html [and_then]: https://doc.rust-lang.org/std/option/enum.Option.html#method.and_then +[flatten]: https://doc.rust-lang.org/std/option/enum.Option.html#method.flatten diff --git a/src/doc/rust-by-example/src/flow_control/let_else.md b/src/doc/rust-by-example/src/flow_control/let_else.md index bc21723c7..bf1a53bde 100644 --- a/src/doc/rust-by-example/src/flow_control/let_else.md +++ b/src/doc/rust-by-example/src/flow_control/let_else.md @@ -2,6 +2,9 @@ > 🛈 stable since: rust 1.65 +> +> 🛈 you can target specific edition by compiling like this +> `rustc --edition=2021 main.rs` With `let`-`else`, a refutable pattern can match and bind variables @@ -22,7 +25,9 @@ fn get_count_item(s: &str) -> (u64, &str) { (count, item) } -assert_eq!(get_count_item("3 chairs"), (3, "chairs")); +fn main() { + assert_eq!(get_count_item("3 chairs"), (3, "chairs")); +} ``` The scope of name bindings is the main thing that makes this different from diff --git a/src/doc/rust-by-example/src/flow_control/match/destructuring/destructure_structures.md b/src/doc/rust-by-example/src/flow_control/match/destructuring/destructure_structures.md index 9e43b70c1..252104fef 100644 --- a/src/doc/rust-by-example/src/flow_control/match/destructuring/destructure_structures.md +++ b/src/doc/rust-by-example/src/flow_control/match/destructuring/destructure_structures.md @@ -24,6 +24,12 @@ fn main() { // this will give an error: pattern does not mention field `x` //Foo { y } => println!("y = {}", y), } + + let faa = Foo { x: (1, 2), y: 3 }; + + // You do not need a match block to destructure structs: + let Foo { x : x0, y: y0 } = faa; + println!("Outside: x0 = {x0:?}, y0 = {y0}"); } ``` diff --git a/src/doc/rust-by-example/src/fn/closures/closure_examples/iter_find.md b/src/doc/rust-by-example/src/fn/closures/closure_examples/iter_find.md index 0a79f7c9d..c3605d784 100644 --- a/src/doc/rust-by-example/src/fn/closures/closure_examples/iter_find.md +++ b/src/doc/rust-by-example/src/fn/closures/closure_examples/iter_find.md @@ -39,9 +39,9 @@ fn main() { let array1 = [1, 2, 3]; let array2 = [4, 5, 6]; - // `iter()` for arrays yields `&i32` + // `iter()` for arrays yields `&&i32` println!("Find 2 in array1: {:?}", array1.iter() .find(|&&x| x == 2)); - // `into_iter()` for arrays yields `i32` + // `into_iter()` for arrays yields `&i32` println!("Find 2 in array2: {:?}", array2.into_iter().find(|&x| x == 2)); } ``` diff --git a/src/doc/rust-by-example/src/hello/print.md b/src/doc/rust-by-example/src/hello/print.md index bf23a9023..ef25dab0e 100644 --- a/src/doc/rust-by-example/src/hello/print.md +++ b/src/doc/rust-by-example/src/hello/print.md @@ -88,7 +88,7 @@ for these types. To print text for custom types, more steps are required. Implementing the `fmt::Display` trait automatically implements the [`ToString`] trait which allows us to [convert] the type to [`String`][string]. -In *line 46*, `#[allow(dead_code)]` is an [attribute] which only apply to the module after it. +In *line 43*, `#[allow(dead_code)]` is an [attribute] which only apply to the module after it. ### Activities diff --git a/src/doc/rust-by-example/src/types/cast.md b/src/doc/rust-by-example/src/types/cast.md index 3078d82c1..7e944d04c 100644 --- a/src/doc/rust-by-example/src/types/cast.md +++ b/src/doc/rust-by-example/src/types/cast.md @@ -53,7 +53,7 @@ fn main() { // Unless it already fits, of course. println!(" 128 as a i16 is: {}", 128 as i16); - // 128 as u8 -> 128, whose value in 8-bit two's complement representation is: + // In boundary case 128 value in 8-bit two's complement representation is -128 println!(" 128 as a i8 is : {}", 128 as i8); // repeating the example above diff --git a/src/doc/rust-by-example/src/unsafe/asm.md b/src/doc/rust-by-example/src/unsafe/asm.md index 1a3fab904..cbe52c840 100644 --- a/src/doc/rust-by-example/src/unsafe/asm.md +++ b/src/doc/rust-by-example/src/unsafe/asm.md @@ -254,7 +254,8 @@ fn main() { // String is stored as ascii in ebx, edx, ecx in order // Because ebx is reserved, the asm needs to preserve the value of it. // So we push and pop it around the main asm. - // (in 64 bit mode for 64 bit processors, 32 bit processors would use ebx) + // 64 bit mode on 64 bit processors does not allow pushing/popping of + // 32 bit registers (like ebx), so we have to use the extended rbx register instead. unsafe { asm!( @@ -474,4 +475,4 @@ Options can be provided as an optional final argument to the `asm!` macro. We sp These allow the compiler to better optimize code using `asm!`, for example by eliminating pure `asm!` blocks whose outputs are not needed. -See the [reference](../../reference/inline-assembly.html) for the full list of available options and their effects. +See the [reference](https://doc.rust-lang.org/stable/reference/inline-assembly.html) for the full list of available options and their effects. diff --git a/src/doc/rustc-dev-guide/src/SUMMARY.md b/src/doc/rustc-dev-guide/src/SUMMARY.md index 58a476bdc..9f7c9cf1b 100644 --- a/src/doc/rustc-dev-guide/src/SUMMARY.md +++ b/src/doc/rustc-dev-guide/src/SUMMARY.md @@ -123,6 +123,7 @@ - [The solver](./solve/the-solver.md) - [Canonicalization](./solve/canonicalization.md) - [Coinduction](./solve/coinduction.md) + - [Proof trees](./solve/proof-trees.md) - [Type checking](./type-checking.md) - [Method Lookup](./method-lookup.md) - [Variance](./variance.md) diff --git a/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md b/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md index 21554f5a4..cf100a2e5 100644 --- a/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md +++ b/src/doc/rustc-dev-guide/src/backend/implicit-caller-location.md @@ -260,7 +260,7 @@ originally specified. They have since been implemented following the path which to the author and reviewers. [RFC 2091]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md -[attr-reference]: https://doc.rust-lang.org/reference/attributes/diagnostics.html#the-track_caller-attribute +[attr-reference]: https://doc.rust-lang.org/reference/attributes/codegen.html#the-track_caller-attribute [intrinsic]: https://doc.rust-lang.org/nightly/core/intrinsics/fn.caller_location.html [wrapper]: https://doc.rust-lang.org/nightly/core/panic/struct.Location.html#method.caller [non-viable alternatives]: https://github.com/rust-lang/rfcs/blob/master/text/2091-inline-semantic.md#non-viable-alternatives diff --git a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md index eb674c8fe..6444aab5f 100644 --- a/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md +++ b/src/doc/rustc-dev-guide/src/building/how-to-build-and-run.md @@ -67,8 +67,11 @@ You can install it with `cargo install --path src/tools/x`. ## Create a `config.toml` -To start, run `./x.py setup`. This will do some initialization and create a -`config.toml` for you with reasonable defaults. +To start, run `./x.py setup` and select the `compiler` defaults. This will do some initialization +and create a `config.toml` for you with reasonable defaults. If you use a different default (which +you'll likely want to do if you want to contribute to an area of rust other than the compiler, such +as rustdoc), make sure to read information about that default (located in `src/bootstrap/defaults`) +as the build process may be different for other defaults. Alternatively, you can write `config.toml` by hand. See `config.example.toml` for all the available settings and explanations of them. See `src/bootstrap/defaults` for common settings to change. diff --git a/src/doc/rustc-dev-guide/src/compiler-team.md b/src/doc/rustc-dev-guide/src/compiler-team.md index 4570fd3fa..d5ba78c77 100644 --- a/src/doc/rustc-dev-guide/src/compiler-team.md +++ b/src/doc/rustc-dev-guide/src/compiler-team.md @@ -124,7 +124,7 @@ for you. [reviewer rotation]: https://github.com/rust-lang/rust/blob/36285c5de8915ecc00d91ae0baa79a87ed5858d5/triagebot.toml#L528-L577 [triagebot]: https://github.com/rust-lang/triagebot/ -[automatically assigns]: https://github.com/rust-lang/triagebot/wiki/Assignment +[automatically assigns]: https://forge.rust-lang.org/triagebot/pr-assignment.html Getting on the reviewer rotation is much appreciated as it lowers the review burden for all of us! However, if you don't have time to give diff --git a/src/doc/rustc-dev-guide/src/const-eval.md b/src/doc/rustc-dev-guide/src/const-eval.md index a7b1c8963..6d301823b 100644 --- a/src/doc/rustc-dev-guide/src/const-eval.md +++ b/src/doc/rustc-dev-guide/src/const-eval.md @@ -56,7 +56,7 @@ The basic rule for being permitted in the type system is that every value must be uniquely represented. In other words: a specific value must only be representable in one specific way. For example: there is only one way to represent an array of two integers as a `ValTree`: -`ValTree::Branch(&[ValTree::Leaf(first_int), ValTree;:Leaf(second_int)])`. +`ValTree::Branch(&[ValTree::Leaf(first_int), ValTree::Leaf(second_int)])`. Even though theoretically a `[u32; 2]` could be encoded in a `u64` and thus just be a `ValTree::Leaf(bits_of_two_u32)`, that is not a legal construction of `ValTree` (and is very complex to do, so it is unlikely anyone is tempted to do so). diff --git a/src/doc/rustc-dev-guide/src/name-resolution.md b/src/doc/rustc-dev-guide/src/name-resolution.md index 1dbc95ead..93c2a3eb7 100644 --- a/src/doc/rustc-dev-guide/src/name-resolution.md +++ b/src/doc/rustc-dev-guide/src/name-resolution.md @@ -91,8 +91,8 @@ part of another, it doesn't mean the name visible in the outer one is also visible in the inner one, or that it refers to the same thing. To cope with that, the compiler introduces the concept of Ribs. This is -abstraction of a scope. Every time the set of visible names potentially changes, -a new rib is pushed onto a stack. The places where this can happen includes for +an abstraction of a scope. Every time the set of visible names potentially changes, +a new rib is pushed onto a stack. The places where this can happen include for example: * The obvious places ‒ curly braces enclosing a block, function boundaries, @@ -103,8 +103,8 @@ example: When searching for a name, the stack of ribs is traversed from the innermost outwards. This helps to find the closest meaning of the name (the one not -shadowed by anything else). The transition to outer rib may also change the -rules what names are usable ‒ if there are nested functions (not closures), +shadowed by anything else). The transition to outer rib may also affect +what names are usable ‒ if there are nested functions (not closures), the inner one can't access parameters and local bindings of the outer one, even though they should be visible by ordinary scoping rules. An example: diff --git a/src/doc/rustc-dev-guide/src/notification-groups/about.md b/src/doc/rustc-dev-guide/src/notification-groups/about.md index 260c59c24..a85c4a505 100644 --- a/src/doc/rustc-dev-guide/src/notification-groups/about.md +++ b/src/doc/rustc-dev-guide/src/notification-groups/about.md @@ -14,7 +14,7 @@ Of course, you don't have to wait for new issues to be tagged! If you prefer, you can use the Github label for a notification group to search for existing issues that haven't been claimed yet. -[claim the issue]: https://github.com/rust-lang/triagebot/wiki/Assignment +[claim the issue]: https://forge.rust-lang.org/triagebot/issue-assignment.html ## List of notification groups @@ -95,5 +95,5 @@ or contributors, and is typically done as part of compiler team triage.** [rustbot]: https://github.com/rust-lang/triagebot/ -[`ping`]: https://github.com/rust-lang/triagebot/wiki/Pinging +[`ping`]: https://forge.rust-lang.org/triagebot/pinging.html [`triagebot.toml`]: https://github.com/rust-lang/rust/blob/master/triagebot.toml diff --git a/src/doc/rustc-dev-guide/src/rustbot.md b/src/doc/rustc-dev-guide/src/rustbot.md index 5350f44ef..0959224f0 100644 --- a/src/doc/rustc-dev-guide/src/rustbot.md +++ b/src/doc/rustc-dev-guide/src/rustbot.md @@ -44,13 +44,13 @@ the `@rustbot` command will look like this: @rustbot label -S-waiting-on-author +S-waiting-on-review The syntax for this command is pretty loose, so there are other variants of this -command invocation. For more details, see [the wiki page about labeling][labeling]. +command invocation. For more details, see [the docs page about labeling][labeling]. -[labeling]: https://github.com/rust-lang/triagebot/wiki/Labeling +[labeling]: https://forge.rust-lang.org/triagebot/labeling.html ## Other commands -If you are interested in seeing what `@rustbot` is capable of, check out its [wiki], +If you are interested in seeing what `@rustbot` is capable of, check out its [documentation], which is meant as a reference for the bot and should be kept up to date every time the bot gets an upgrade. @@ -58,6 +58,6 @@ bot gets an upgrade. existing commands or suggestions for new commands, feel free to reach out [on Zulip][zulip] or file an issue in [the triagebot repository][repo] -[wiki]: https://github.com/rust-lang/triagebot/wiki +[documentation]: https://forge.rust-lang.org/triagebot/index.html [zulip]: https://rust-lang.zulipchat.com/#narrow/stream/224082-t-release.2Ftriagebot [repo]: https://github.com/rust-lang/triagebot/ diff --git a/src/doc/rustc-dev-guide/src/solve/proof-trees.md b/src/doc/rustc-dev-guide/src/solve/proof-trees.md new file mode 100644 index 000000000..e0904d946 --- /dev/null +++ b/src/doc/rustc-dev-guide/src/solve/proof-trees.md @@ -0,0 +1,50 @@ +# Proof trees + +The trait solver can optionally emit a "proof tree", a tree representation of what +happened while trying to prove a goal. + +The used datastructures for which are currently stored in +[`rustc_middle::traits::solve::inspect`]. + +## What are they used for + +There are 3 intended uses for proof trees. These uses are not yet implemented as +the representation of proof trees itself is currently still unstable. + +They should be used by type system diagnostics to get information about +why a goal failed or remained ambiguous. They should be used by rustdoc to get the +auto-trait implementations for user-defined types, and they should be usable to +vastly improve the debugging experience of the trait solver. + +For debugging you can use `-Zdump-solver-proof-tree` which dumps the proof tree +for all goals proven by the trait solver in the current session. + +## Requirements and design constraints for proof trees + +The trait solver uses [Canonicalization] and uses completely separate `InferCtxt` for +each nested goal. Both diagnostics and auto-traits in rustdoc need to correctly +handle "looking into nested goals". Given a goal like `Vec<Vec<?x>>: Debug`, we +canonicalize to `exists<T0> Vec<Vec<T0>>: Debug`, instantiate that goal as +`Vec<Vec<?0>>: Debug`, get a nested goal `Vec<?0>: Debug`, canonicalize this to get +`exists<T0> Vec<T0>: Debug`, instantiate this as `Vec<?0>: Debug` which then results +in a nested `?0: Debug` goal which is ambiguous. + +We need to be able to figure out that `?x` corresponds to `?0` in the nested queries. + +The debug output should also accurately represent the state at each point in the solver. +This means that even though a goal like `fn(?0): FnOnce(i32)` infers `?0` to `i32`, the +proof tree should still store `fn(<some infer var>): FnOnce(i32)` instead of +`fn(i32): FnOnce(i32)` until we actually infer `?0` to `i32`. + +## The current implementation and how to extract information from proof trees. + +Proof trees will be quite involved as they should accurately represent everything the +trait solver does, which includes fixpoint iterations and performance optimizations. + +We intend to provide a lossy user interface for all usecases. + +TODO: implement this user interface and explain how it can be used here. + + +[`rustc_middle::traits::solve::inspect`]: https://doc.rust-lang.org/nightly/nightly-rustc/rustc_middle/traits/solve/inspect/index.html +[Canonicalization]: ./canonicalization.md
\ No newline at end of file diff --git a/src/doc/rustc-dev-guide/src/tests/compiletest.md b/src/doc/rustc-dev-guide/src/tests/compiletest.md index f066992dc..d4730c5b4 100644 --- a/src/doc/rustc-dev-guide/src/tests/compiletest.md +++ b/src/doc/rustc-dev-guide/src/tests/compiletest.md @@ -363,7 +363,7 @@ your test, causing separate files to be generated for 32bit and 64bit systems. [`tests/mir-opt`]: https://github.com/rust-lang/rust/tree/master/tests/mir-opt -### Run-make tests +### `run-make` tests The tests in [`tests/run-make`] are general-purpose tests using Makefiles which provide the ultimate in flexibility. @@ -371,8 +371,8 @@ These should be used as a last resort. If possible, you should use one of the other test suites. If there is some minor feature missing which you need for your test, consider extending compiletest to add a header command for what you need. -However, sometimes just running a bunch of commands is really what you -need, `run-make` is here to the rescue! +However, if running a bunch of commands is really what you need, +`run-make` is here to the rescue! Each test should be in a separate directory with a `Makefile` indicating the commands to run. diff --git a/src/doc/rustc-dev-guide/src/thir.md b/src/doc/rustc-dev-guide/src/thir.md index 2a811be3d..2197cad71 100644 --- a/src/doc/rustc-dev-guide/src/thir.md +++ b/src/doc/rustc-dev-guide/src/thir.md @@ -82,7 +82,7 @@ Thir { neg: false, }, }, - // expression 1, scope surronding literal 1 + // expression 1, scope surrounding literal 1 Expr { ty: i32, temp_lifetime: Some( diff --git a/src/doc/rustc-dev-guide/src/traits/resolution.md b/src/doc/rustc-dev-guide/src/traits/resolution.md index 639ebbdec..8fd4272a8 100644 --- a/src/doc/rustc-dev-guide/src/traits/resolution.md +++ b/src/doc/rustc-dev-guide/src/traits/resolution.md @@ -247,7 +247,7 @@ In this second selection, we do not consider any where-clauses to be in scope because we know that each resolution will resolve to a particular impl. One interesting twist has to do with nested obligations. In general, in codegen, -we only to figure out which candidate applies, we do not care about nested obligations, +we only need to figure out which candidate applies, and we do not care about nested obligations, as these are already assumed to be true. Nonetheless, we *do* currently fulfill all of them. That is because it can sometimes inform the results of type inference. That is, we do not have the full substitutions in terms of the type variables diff --git a/src/doc/rustc/src/SUMMARY.md b/src/doc/rustc/src/SUMMARY.md index 73343ba9d..f8af26326 100644 --- a/src/doc/rustc/src/SUMMARY.md +++ b/src/doc/rustc/src/SUMMARY.md @@ -16,6 +16,7 @@ - [Target Tier Policy](target-tier-policy.md) - [Template for Target-specific Documentation](platform-support/TEMPLATE.md) - [aarch64-apple-ios-sim](platform-support/aarch64-apple-ios-sim.md) + - [\*-apple-tvos](platform-support/apple-tvos.md) - [\*-apple-watchos\*](platform-support/apple-watchos.md) - [aarch64-nintendo-switch-freestanding](platform-support/aarch64-nintendo-switch-freestanding.md) - [armeb-unknown-linux-gnueabi](platform-support/armeb-unknown-linux-gnueabi.md) @@ -31,6 +32,7 @@ - [\*-unknown-fuchsia](platform-support/fuchsia.md) - [\*-kmc-solid_\*](platform-support/kmc-solid.md) - [loongarch\*-unknown-linux-\*](platform-support/loongarch-linux.md) + - [loongarch\*-unknown-none\*](platform-support/loongarch-none.md) - [m68k-unknown-linux-gnu](platform-support/m68k-unknown-linux-gnu.md) - [mips64-openwrt-linux-musl](platform-support/mips64-openwrt-linux-musl.md) - [mipsel-sony-psx](platform-support/mipsel-sony-psx.md) @@ -38,6 +40,7 @@ - [riscv32imac-unknown-xous-elf](platform-support/riscv32imac-unknown-xous-elf.md) - [*-pc-windows-gnullvm](platform-support/pc-windows-gnullvm.md) - [\*-nto-qnx-\*](platform-support/nto-qnx.md) + - [\*-unknown-netbsd\*](platform-support/netbsd.md) - [*-unknown-openbsd](platform-support/openbsd.md) - [\*-unknown-uefi](platform-support/unknown-uefi.md) - [wasm64-unknown-unknown](platform-support/wasm64-unknown-unknown.md) diff --git a/src/doc/rustc/src/codegen-options/index.md b/src/doc/rustc/src/codegen-options/index.md index 1041d5026..8de638dde 100644 --- a/src/doc/rustc/src/codegen-options/index.md +++ b/src/doc/rustc/src/codegen-options/index.md @@ -31,8 +31,8 @@ Supported values can also be discovered by running `rustc --print code-models`. ## codegen-units -This flag controls how many code generation units the crate is split into. It -takes an integer greater than 0. +This flag controls the maximum number of code generation units the crate is +split into. It takes an integer greater than 0. When a crate is split into multiple codegen units, LLVM is able to process them in parallel. Increasing parallelism may speed up compile times, but may diff --git a/src/doc/rustc/src/command-line-arguments.md b/src/doc/rustc/src/command-line-arguments.md index 3be4382b0..2c7c05c0c 100644 --- a/src/doc/rustc/src/command-line-arguments.md +++ b/src/doc/rustc/src/command-line-arguments.md @@ -58,8 +58,8 @@ Example: `-l static:+whole-archive=mylib`. The kind of library and the modifiers can also be specified in a [`#[link]` attribute][link-attribute]. If the kind is not specified in the `link` -attribute or on the command-line, it will link a dynamic library if available, -otherwise it will use a static library. If the kind is specified on the +attribute or on the command-line, it will link a dynamic library by default, +except when building a static executable. If the kind is specified on the command-line, it will override the kind specified in a `link` attribute. The name used in a `link` attribute may be overridden using the form `-l @@ -202,6 +202,12 @@ flag](codegen-options/index.md#extra-filename). The files are written to the current directory unless the [`--out-dir` flag](#option-out-dir) is used. Each emission type may also specify the output filename with the form `KIND=PATH`, which takes precedence over the `-o` flag. +Specifying `-o -` or `--emit KIND=-` asks rustc to emit to stdout. +Text output types (`asm`, `dep-info`, `llvm-ir` and `mir`) can be written to +stdout despite it being a tty or not. This will result in an error if any +binary output type is written to stdout that is a tty. +This will also result in an error if multiple output types +would be written to stdout, because they would be all mixed together. [LLVM bitcode]: https://llvm.org/docs/BitCodeFormat.html [LLVM IR]: https://llvm.org/docs/LangRef.html diff --git a/src/doc/rustc/src/exploit-mitigations.md b/src/doc/rustc/src/exploit-mitigations.md index a82a53248..172048704 100644 --- a/src/doc/rustc/src/exploit-mitigations.md +++ b/src/doc/rustc/src/exploit-mitigations.md @@ -55,88 +55,18 @@ Table I \ Summary of exploit mitigations supported by the Rust compiler when building programs for the Linux operating system on the AMD64 architecture and equivalent. -<table class="table"> - <tr> - <td><strong>Exploit mitigation</strong> - </td> - <td><strong>Supported and enabled by default</strong> - </td> - <td><strong>Since</strong> - </td> - </tr> - <tr> - <td>Position-independent executable - </td> - <td>Yes - </td> - <td>0.12.0 (2014-10-09) - </td> - </tr> - <tr> - <td>Integer overflow checks - </td> - <td>Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled) - </td> - <td>1.1.0 (2015-06-25) - </td> - </tr> - <tr> - <td>Non-executable memory regions - </td> - <td>Yes - </td> - <td>1.8.0 (2016-04-14) - </td> - </tr> - <tr> - <td>Stack clashing protection - </td> - <td>Yes - </td> - <td>1.20.0 (2017-08-31) - </td> - </tr> - <tr> - <td>Read-only relocations and immediate binding - </td> - <td>Yes - </td> - <td>1.21.0 (2017-10-12) - </td> - </tr> - <tr> - <td>Heap corruption protection - </td> - <td>Yes - </td> - <td>1.32.0 (2019-01-17) (via operating system default or specified allocator) - </td> - </tr> - <tr> - <td>Stack smashing protection - </td> - <td>Yes - </td> - <td>Nightly - </td> - </tr> - <tr> - <td>Forward-edge control flow protection - </td> - <td>Yes - </td> - <td>Nightly - </td> - </tr> - <tr> - <td>Backward-edge control flow protection (e.g., shadow and safe stack) - </td> - <td>No - </td> - <td> - </td> - </tr> -</table> + +| Exploit mitigation | Supported and enabled by default | Since | +| - | - | - | +| Position-independent executable | Yes | 0.12.0 (2014-10-09) | +| Integer overflow checks | Yes (enabled when debug assertions are enabled, and disabled when debug assertions are disabled) | 1.1.0 (2015-06-25) | +| Non-executable memory regions | Yes | 1.8.0 (2016-04-14) | +| Stack clashing protection | Yes | 1.20.0 (2017-08-31) | +| Read-only relocations and immediate binding | Yes | 1.21.0 (2017-10-12) | +| Heap corruption protection | Yes | 1.32.0 (2019-01-17) (via operating system default or specified allocator) | +| Stack smashing protection | Yes | Nightly | +| Forward-edge control flow protection | Yes | Nightly | +| Backward-edge control flow protection (e.g., shadow and safe stack) | Yes | Nightly | <small id="fn:1">1\. See <https://github.com/rust-lang/rust/tree/master/compiler/rustc_target/src/spec> @@ -513,20 +443,21 @@ Newer processors provide hardware assistance for backward-edge control flow protection, such as ARM Pointer Authentication, and Intel Shadow Stack as part of Intel CET. -The Rust compiler does not support shadow or safe stack. There is work -currently ongoing to add support for the sanitizers[40], which may or may -not include support for safe stack<sup id="fnref:7" role="doc-noteref"><a -href="#fn:7" class="footnote">7</a></sup>. +The Rust compiler supports shadow stack for aarch64 only +<sup id="fnref:7" role="doc-noteref"><a href="#fn:7" class="footnote">7</a></sup> +on nightly Rust compilers [43]-[44]. Safe stack is available on nightly +Rust compilers [45]-[46]. ```text $ readelf -s target/release/hello-rust | grep __safestack_init + 1177: 00000000000057b0 444 FUNC GLOBAL DEFAULT 9 __safestack_init ``` Fig. 16. Checking if LLVM SafeStack is enabled for a given binary. The presence of the `__safestack_init` symbol indicates that LLVM SafeStack -is enabled for a given binary. Conversely, the absence of the +is enabled for a given binary (see Fig. 16). Conversely, the absence of the `__safestack_init` symbol indicates that LLVM SafeStack is not enabled for a -given binary (see Fig. 16). +given binary. <small id="fn:7">7\. The shadow stack implementation for the AMD64 architecture and equivalent in LLVM was removed due to performance and @@ -698,3 +629,15 @@ defaults (unrelated to `READ_IMPLIES_EXEC`). 42. bbjornse. “add codegen option for using LLVM stack smash protection #84197.” GitHub. <https://github.com/rust-lang/rust/pull/84197> + +43. ivanloz. “Add support for LLVM ShadowCallStack. #98208.” GitHub. + <https://github.com/rust-lang/rust/pull/98208>. + +44. “ShadowCallStack.” The Rust Unstable Book. + [https://doc.rust-lang.org/unstable-book/compiler-flags/sanitizer.html#shadowcallstack](../unstable-book/compiler-flags/sanitizer.html#shadowcallstack). + +45. W. Wiser. “Add support for LLVM SafeStack #112000” GitHub. + <https://github.com/rust-lang/rust/pull/112000> + +46. “SafeStack.” The Rust Unstable Book. + [https://doc.rust-lang/org/unstable-book/compiler-flags/sanitizer.html#safestack](../unstable-book/compiler-flags/sanitizer.html#safestack). diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 3b2463aa5..d2a25e612 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -87,7 +87,7 @@ target | notes `aarch64-unknown-linux-musl` | ARM64 Linux with MUSL `arm-unknown-linux-gnueabi` | ARMv6 Linux (kernel 3.2, glibc 2.17) `arm-unknown-linux-gnueabihf` | ARMv6 Linux, hardfloat (kernel 3.2, glibc 2.17) -`armv7-unknown-linux-gnueabihf` | ARMv7 Linux, hardfloat (kernel 3.2, glibc 2.17) +`armv7-unknown-linux-gnueabihf` | ARMv7-A Linux, hardfloat (kernel 3.2, glibc 2.17) [`loongarch64-unknown-linux-gnu`](platform-support/loongarch-linux.md) | LoongArch64 Linux, LP64D ABI (kernel 5.19, glibc 2.36) `mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23) `mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23) @@ -133,17 +133,17 @@ target | std | notes `aarch64-unknown-none-softfloat` | * | Bare ARM64, softfloat `aarch64-unknown-none` | * | Bare ARM64, hardfloat [`aarch64-unknown-uefi`](platform-support/unknown-uefi.md) | * | ARM64 UEFI -[`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7 Android +[`arm-linux-androideabi`](platform-support/android.md) | ✓ | ARMv6 Android `arm-unknown-linux-musleabi` | ✓ | ARMv6 Linux with MUSL `arm-unknown-linux-musleabihf` | ✓ | ARMv6 Linux with MUSL, hardfloat `armebv7r-none-eabi` | * | Bare ARMv7-R, Big Endian `armebv7r-none-eabihf` | * | Bare ARMv7-R, Big Endian, hardfloat `armv5te-unknown-linux-gnueabi` | ✓ | ARMv5TE Linux (kernel 4.4, glibc 2.23) `armv5te-unknown-linux-musleabi` | ✓ | ARMv5TE Linux with MUSL -[`armv7-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7a Android -`armv7-unknown-linux-gnueabi` | ✓ |ARMv7 Linux (kernel 4.15, glibc 2.27) -`armv7-unknown-linux-musleabi` | ✓ |ARMv7 Linux with MUSL -`armv7-unknown-linux-musleabihf` | ✓ | ARMv7 Linux with MUSL, hardfloat +[`armv7-linux-androideabi`](platform-support/android.md) | ✓ | ARMv7-A Android +`armv7-unknown-linux-gnueabi` | ✓ | ARMv7-A Linux (kernel 4.15, glibc 2.27) +`armv7-unknown-linux-musleabi` | ✓ | ARMv7-A Linux with MUSL +`armv7-unknown-linux-musleabihf` | ✓ | ARMv7-A Linux with MUSL, hardfloat `armv7a-none-eabi` | * | Bare ARMv7-A `armv7r-none-eabi` | * | Bare ARMv7-R `armv7r-none-eabihf` | * | Bare ARMv7-R, hardfloat @@ -167,15 +167,15 @@ target | std | notes `riscv64imac-unknown-none-elf` | * | Bare RISC-V (RV64IMAC ISA) `sparc64-unknown-linux-gnu` | ✓ | SPARC Linux (kernel 4.4, glibc 2.23) `sparcv9-sun-solaris` | ✓ | SPARC Solaris 10/11, illumos -`thumbv6m-none-eabi` | * | Bare Cortex-M0, M0+, M1 -`thumbv7em-none-eabi` | * | Bare Cortex-M4, M7 -`thumbv7em-none-eabihf` | * | Bare Cortex-M4F, M7F, FPU, hardfloat -`thumbv7m-none-eabi` | * | Bare Cortex-M3 -[`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode ARMv7a Android with NEON -`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7a Linux with NEON (kernel 4.4, glibc 2.23) -`thumbv8m.base-none-eabi` | * | ARMv8-M Baseline -`thumbv8m.main-none-eabi` | * | ARMv8-M Mainline -`thumbv8m.main-none-eabihf` | * | ARMv8-M Mainline, hardfloat +`thumbv6m-none-eabi` | * | Bare ARMv6-M +`thumbv7em-none-eabi` | * | Bare ARMv7E-M +`thumbv7em-none-eabihf` | * | Bare ARMV7E-M, hardfloat +`thumbv7m-none-eabi` | * | Bare ARMv7-M +[`thumbv7neon-linux-androideabi`](platform-support/android.md) | ✓ | Thumb2-mode ARMv7-A Android with NEON +`thumbv7neon-unknown-linux-gnueabihf` | ✓ | Thumb2-mode ARMv7-A Linux with NEON (kernel 4.4, glibc 2.23) +`thumbv8m.base-none-eabi` | * | Bare ARMv8-M Baseline +`thumbv8m.main-none-eabi` | * | Bare ARMv8-M Mainline +`thumbv8m.main-none-eabihf` | * | Bare ARMv8-M Mainline, hardfloat `wasm32-unknown-emscripten` | ✓ | WebAssembly via Emscripten `wasm32-unknown-unknown` | ✓ | WebAssembly `wasm32-wasi` | ✓ | WebAssembly with WASI @@ -214,7 +214,7 @@ host tools. target | std | host | notes -------|:---:|:----:|------- `aarch64-apple-ios-macabi` | ? | | Apple Catalyst on ARM64 -`aarch64-apple-tvos` | * | | ARM64 tvOS +[`aarch64-apple-tvos`](platform-support/apple-tvos.md) | ? | | ARM64 tvOS [`aarch64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | ARM64 Apple WatchOS Simulator [`aarch64-kmc-solid_asp3`](platform-support/kmc-solid.md) | ✓ | | ARM64 SOLID with TOPPERS/ASP3 [`aarch64-nintendo-switch-freestanding`](platform-support/aarch64-nintendo-switch-freestanding.md) | * | | ARM64 Nintendo Switch, Horizon @@ -224,35 +224,36 @@ target | std | host | notes `aarch64-unknown-freebsd` | ✓ | ✓ | ARM64 FreeBSD `aarch64-unknown-hermit` | ✓ | | ARM64 HermitCore `aarch64-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (ILP32 ABI) -`aarch64-unknown-netbsd` | ✓ | ✓ | +[`aarch64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD [`aarch64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | ARM64 OpenBSD `aarch64-unknown-redox` | ? | | ARM64 Redox OS `aarch64-uwp-windows-msvc` | ? | | `aarch64-wrs-vxworks` | ? | | `aarch64_be-unknown-linux-gnu_ilp32` | ✓ | ✓ | ARM64 Linux (big-endian, ILP32 ABI) `aarch64_be-unknown-linux-gnu` | ✓ | ✓ | ARM64 Linux (big-endian) +[`aarch64_be-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | ARM64 NetBSD (big-endian) [`arm64_32-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS 64-bit with 32-bit pointers [`armeb-unknown-linux-gnueabi`](platform-support/armeb-unknown-linux-gnueabi.md) | ✓ | ? | ARM BE8 the default ARM big-endian architecture since [ARMv6](https://developer.arm.com/documentation/101754/0616/armlink-Reference/armlink-Command-line-Options/--be8?lang=en). -`armv4t-none-eabi` | * | | ARMv4T A32 -`armv4t-unknown-linux-gnueabi` | ? | | -[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | ARMv5TE A32 +`armv4t-none-eabi` | * | | Bare ARMv4T +`armv4t-unknown-linux-gnueabi` | ? | | ARMv4T Linux +[`armv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Bare ARMv5TE `armv5te-unknown-linux-uclibceabi` | ? | | ARMv5TE Linux with uClibc `armv6-unknown-freebsd` | ✓ | ✓ | ARMv6 FreeBSD -`armv6-unknown-netbsd-eabihf` | ? | | +[`armv6-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv6 NetBSD w/hard-float [`armv6k-nintendo-3ds`](platform-support/armv6k-nintendo-3ds.md) | ? | | ARMv6K Nintendo 3DS, Horizon (Requires devkitARM toolchain) -`armv7-apple-ios` | ✓ | | ARMv7 iOS, Cortex-a8 -[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ? | | ARM Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) -[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | ARMv7 OpenHarmony | -[`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7 Linux with uClibc, softfloat -[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7 Linux with uClibc, hardfloat -`armv7-unknown-freebsd` | ✓ | ✓ | ARMv7 FreeBSD -`armv7-unknown-netbsd-eabihf` | ✓ | ✓ | -`armv7-wrs-vxworks-eabihf` | ? | | +`armv7-apple-ios` | ✓ | | ARMv7-A Cortex-A8 iOS +[`armv7-sony-vita-newlibeabihf`](platform-support/armv7-sony-vita-newlibeabihf.md) | ? | | ARMv7-A Cortex-A9 Sony PlayStation Vita (requires VITASDK toolchain) +[`armv7-unknown-linux-ohos`](platform-support/openharmony.md) | ✓ | | ARMv7-A OpenHarmony | +[`armv7-unknown-linux-uclibceabi`](platform-support/armv7-unknown-linux-uclibceabi.md) | ✓ | ✓ | ARMv7-A Linux with uClibc, softfloat +[`armv7-unknown-linux-uclibceabihf`](platform-support/armv7-unknown-linux-uclibceabihf.md) | ✓ | ? | ARMv7-A Linux with uClibc, hardfloat +`armv7-unknown-freebsd` | ✓ | ✓ | ARMv7-A FreeBSD +[`armv7-unknown-netbsd-eabihf`](platform-support/netbsd.md) | ✓ | ✓ | ARMv7-A NetBSD w/hard-float +`armv7-wrs-vxworks-eabihf` | ? | | ARMv7-A for VxWorks [`armv7a-kmc-solid_asp3-eabi`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3 [`armv7a-kmc-solid_asp3-eabihf`](platform-support/kmc-solid.md) | ✓ | | ARM SOLID with TOPPERS/ASP3, hardfloat -`armv7a-none-eabihf` | * | | ARM Cortex-A, hardfloat -[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARM Apple WatchOS -`armv7s-apple-ios` | ✓ | | +`armv7a-none-eabihf` | * | | Bare ARMv7-A, hardfloat +[`armv7k-apple-watchos`](platform-support/apple-watchos.md) | ✓ | | ARMv7-A Apple WatchOS +`armv7s-apple-ios` | ✓ | | ARMv7-A Apple-A6 Apple iOS `avr-unknown-gnu-atmega328` | * | | AVR. Requires `-Z build-std=core` `bpfeb-unknown-none` | * | | BPF (big endian) `bpfel-unknown-none` | * | | BPF (little endian) @@ -262,11 +263,13 @@ target | std | host | notes `i686-apple-darwin` | ✓ | ✓ | 32-bit macOS (10.7+, Lion+) `i686-pc-windows-msvc` | * | | 32-bit Windows XP support `i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku -`i686-unknown-netbsd` | ✓ | ✓ | NetBSD/i386 with SSE2 +[`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD `i686-uwp-windows-gnu` | ? | | `i686-uwp-windows-msvc` | ? | | `i686-wrs-vxworks` | ? | | +[`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI) +[`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64S ABI) [`m68k-unknown-linux-gnu`](platform-support/m68k-unknown-linux-gnu.md) | ? | | Motorola 680x0 Linux `mips-unknown-linux-uclibc` | ✓ | | MIPS Linux with uClibc [`mips64-openwrt-linux-musl`](platform-support/mips64-openwrt-linux-musl.md) | ? | | MIPS64 for OpenWrt Linux MUSL @@ -281,7 +284,7 @@ target | std | host | notes `msp430-none-elf` | * | | 16-bit MSP430 microcontrollers `powerpc-unknown-linux-gnuspe` | ✓ | | PowerPC SPE Linux `powerpc-unknown-linux-musl` | ? | | -`powerpc-unknown-netbsd` | ✓ | ✓ | +[`powerpc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD 32-bit powerpc systems `powerpc-unknown-openbsd` | ? | | `powerpc-wrs-vxworks-spe` | ? | | `powerpc-wrs-vxworks` | ? | | @@ -298,22 +301,24 @@ target | std | host | notes `riscv32im-unknown-none-elf` | * | | Bare RISC-V (RV32IM ISA) [`riscv32imac-unknown-xous-elf`](platform-support/riscv32imac-unknown-xous-elf.md) | ? | | RISC-V Xous (RV32IMAC ISA) [`riscv32imc-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF +[`riscv32imac-esp-espidf`](platform-support/esp-idf.md) | ✓ | | RISC-V ESP-IDF `riscv64gc-unknown-freebsd` | | | RISC-V FreeBSD `riscv64gc-unknown-fuchsia` | | | RISC-V Fuchsia `riscv64gc-unknown-linux-musl` | | | RISC-V Linux (kernel 4.20, musl 1.2.0) +[`riscv64gc-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ? | RISC-V NetBSD [`riscv64gc-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/riscv64 `s390x-unknown-linux-musl` | | | S390x Linux (kernel 3.2, MUSL) `sparc-unknown-linux-gnu` | ✓ | | 32-bit SPARC Linux -`sparc64-unknown-netbsd` | ✓ | ✓ | NetBSD/sparc64 +[`sparc64-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/sparc64 [`sparc64-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | OpenBSD/sparc64 -`thumbv4t-none-eabi` | * | | ARMv4T T32 -[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | ARMv5TE T32 +`thumbv4t-none-eabi` | * | | Thumb-mode Bare ARMv4T +[`thumbv5te-none-eabi`](platform-support/armv5te-none-eabi.md) | * | | Thumb-mode Bare ARMv5TE `thumbv7a-pc-windows-msvc` | ? | | `thumbv7a-uwp-windows-msvc` | ✓ | | -`thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7a Linux with NEON, MUSL +`thumbv7neon-unknown-linux-musleabihf` | ? | | Thumb2-mode ARMv7-A Linux with NEON, MUSL [`wasm64-unknown-unknown`](platform-support/wasm64-unknown-unknown.md) | ? | | WebAssembly `x86_64-apple-ios-macabi` | ✓ | | Apple Catalyst on x86_64 -`x86_64-apple-tvos` | * | | x86 64-bit tvOS +[`x86_64-apple-tvos`](platform-support/apple-tvos.md) | ? | | x86 64-bit tvOS [`x86_64-apple-watchos-sim`](platform-support/apple-watchos.md) | ✓ | | x86 64-bit Apple WatchOS simulator [`x86_64-pc-nto-qnx710`](platform-support/nto-qnx.md) | ✓ | | x86 64-bit QNX Neutrino 7.1 RTOS | [`x86_64-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | ✓ | diff --git a/src/doc/rustc/src/platform-support/apple-tvos.md b/src/doc/rustc/src/platform-support/apple-tvos.md new file mode 100644 index 000000000..d87fd1959 --- /dev/null +++ b/src/doc/rustc/src/platform-support/apple-tvos.md @@ -0,0 +1,85 @@ +# `*-apple-tvos` +- aarch64-apple-tvos +- x86_64-apple-tvos + +**Tier: 3** + +Apple tvOS targets: +- Apple tvOS on aarch64 +- Apple tvOS Simulator on x86_64 + +## Target maintainers + +* [@thomcc](https://github.com/thomcc) + +## Requirements + +These targets are cross-compiled. You will need appropriate versions of Xcode +and the SDKs for tvOS (`AppleTVOS.sdk`) and/or the tvOS Simulator +(`AppleTVSimulator.sdk`) to build a toolchain and target these platforms. + +The targets support most (see below) of the standard library including the +allocator to the best of my knowledge, however they are very new, not yet +well-tested, and it is possible that there are various bugs. + +In theory we support back to tvOS version 7.0, although the actual minimum +version you can target may be newer than this, for example due to the versions +of Xcode and your SDKs. + +As with the other Apple targets, `rustc` respects the common environment +variables used by Xcode to configure this, in this case +`TVOS_DEPLOYMENT_TARGET`. + +#### Incompletely supported library functionality + +As mentioned, "most" of the standard library is supported, which means that some portions +are known to be unsupported. The following APIs are currently known to have +missing or incomplete support: + +- `std::process::Command`'s API will return an error if it is configured in a + manner which cannot be performed using `posix_spawn` -- this is because the + more flexible `fork`/`exec`-based approach is prohibited on these platforms in + favor of `posix_spawn{,p}` (which still probably will get you rejected from + app stores, so is likely sideloading-only). A concrete set of cases where this + will occur is difficult to enumerate (and would quickly become stale), but in + some cases it may be worked around by tweaking the manner in which `Command` + is invoked. + +## Building the target + +The targets can be built by enabling them for a `rustc` build in `config.toml`, by adding, for example: + +```toml +[build] +build-stage = 1 +target = ["aarch64-apple-tvos", "x86_64-apple-tvos"] +``` + +It's possible that cargo under `-Zbuild-std` may also be used to target them. + +## Building Rust programs + +*Note: Building for this target requires the corresponding TVOS SDK, as provided by Xcode.* + +Rust programs can be built for these targets + +```text +$ rustc --target aarch64-apple-tvos your-code.rs +... +$ rustc --target x86_64-apple-tvos your-code.rs +``` + +## Testing + +There is no support for running the Rust or standard library testsuite on tvOS +or the simulators at the moment. Testing has mostly been done manually with +builds of static libraries called from Xcode or a simulator. + +It hopefully will be possible to improve this in the future. + +## Cross-compilation toolchains and C code + +This target can be cross-compiled from x86_64 or aarch64 macOS hosts. + +Other hosts are not supported for cross-compilation, but might work when also +providing the required Xcode SDK. diff --git a/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md b/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md index d75bd92be..49eed366d 100644 --- a/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md +++ b/src/doc/rustc/src/platform-support/armv7-sony-vita-newlibeabihf.md @@ -7,7 +7,7 @@ This tier supports the ARM Cortex A9 processor running on a PlayStation Vita con Rust support for this target is not affiliated with Sony, and is not derived from nor used with any official Sony SDK. -## Designated Developers +## Target maintainers * [@amg98](https://github.com/amg98) * [@nikarh](https://github.com/nikarh) @@ -27,9 +27,9 @@ In order to support some APIs, binaries must be linked against `libc` written for the target, using a linker for the target. These are provided by the VITASDK toolchain. -This target generates binaries in the ELF format. +This target generates binaries in the ELF format with thumb ISA. -## Building +## Building the target Rust does not ship pre-compiled artifacts for this target. You can use `build-std` flag to build binaries with `std`: @@ -37,43 +37,9 @@ Rust does not ship pre-compiled artifacts for this target. You can use `build-st cargo build -Z build-std=std,panic_abort --target=armv7-sony-vita-newlibeabihf --release ``` -## Cross-compilation - -This target can be cross-compiled from `x86_64` on either Windows, MacOS or Linux systems. Other hosts are not supported for cross-compilation. - -## Testing - -Currently there is no support to run the rustc test suite for this target. - -## Building and Running Rust Programs +## Building Rust programs -`std` support for this target relies on newlib. In order to work, newlib must be initialized correctly. The easiest way to achieve this with VITASDK newlib implementation is by compiling your program as a staticlib with and exposing your main function from rust to `_init` function in `crt0`. - -Add this to your `Cargo.toml`: - -```toml -[lib] -crate-type = ["staticlib"] - -[profile.release] -panic = 'abort' -lto = true -opt-level = 3 -``` - -Your entrypoint should look roughly like this, `src/lib.rs`: -```rust,ignore,no_run -#[used] -#[export_name = "_newlib_heap_size_user"] -pub static _NEWLIB_HEAP_SIZE_USER: u32 = 100 * 1024 * 1024; // Default heap size is only 32mb, increase it to something suitable for your application - -#[no_mangle] -pub extern "C" fn main() { - println!("Hello, world!"); -} -``` - -To test your developed rust programs on PlayStation Vita, first you must correctly link and package your rust staticlib. These steps can be preformed using tools available in VITASDK, and can be automated using tools like `cargo-make`. +To test your developed rust programs on PlayStation Vita, first you must correctly package your elf. These steps can be preformed using tools available in VITASDK, and can be automated using a tool like `cargo-make`. First, set up environment variables for `VITASDK`, and it's binaries: @@ -88,40 +54,21 @@ Use the example below as a template for your project: [env] TITLE = "Rust Hello World" TITLEID = "RUST00001" -# Add other libs required by your project here -LINKER_LIBS = "-lpthread -lm -lmathneon" # At least a "sce_sys" folder should be place there for app metadata (title, icons, description...) # You can find sample assets for that on $VITASDK/share/gcc-arm-vita-eabi/samples/hello_world/sce_sys/ STATIC_DIR = "static" # Folder where static assets should be placed (sce_sys folder is at $STATIC_DIR/sce_sys) CARGO_TARGET_DIR = { script = ["echo ${CARGO_TARGET_DIR:=target}"] } -RUST_TARGET = "armv7-sony-vita-newlibeabihf" CARGO_OUT_DIR = "${CARGO_TARGET_DIR}/${RUST_TARGET}/release" -TARGET_LINKER = "arm-vita-eabi-gcc" -TARGET_LINKER_FLAGS = "-Wl,-q" - [tasks.build] -description = "Build the project using `cargo` as a static lib." +description = "Build the project using `cargo`." command = "cargo" args = ["build", "-Z", "build-std=std,panic_abort", "--target=armv7-sony-vita-newlibeabihf", "--release"] -[tasks.link] -description = "Build an ELF executable using the `vitasdk` linker." -dependencies = ["build"] -script = [ - """ - ${TARGET_LINKER} ${TARGET_LINKER_FLAGS} \ - -L"${CARGO_OUT_DIR}" \ - -l"${CARGO_MAKE_CRATE_FS_NAME}" \ - ${LINKER_LIBS} \ - -o"${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_NAME}.elf" - """ -] - [tasks.strip] description = "Strip the produced ELF executable." -dependencies = ["link"] +dependencies = ["build"] command = "arm-vita-eabi-strip" args = ["-g", '${CARGO_OUT_DIR}/${CARGO_MAKE_CRATE_FS_NAME}.elf'] @@ -194,3 +141,11 @@ script = [ ``` After running the above script, you should be able to get a *.vpk file in the same folder your *.elf executable resides. Now you can pick it and install it on your own PlayStation Vita using, or you can use an [Vita3K](https://vita3k.org/) emulator. + +## Testing + +Currently there is no support to run the rustc test suite for this target. + +## Cross-compilation + +This target can be cross-compiled from `x86_64` on either Windows, MacOS or Linux systems. Other hosts are not supported for cross-compilation. diff --git a/src/doc/rustc/src/platform-support/esp-idf.md b/src/doc/rustc/src/platform-support/esp-idf.md index 8a4ca347e..8f630fa15 100644 --- a/src/doc/rustc/src/platform-support/esp-idf.md +++ b/src/doc/rustc/src/platform-support/esp-idf.md @@ -13,11 +13,14 @@ Targets for the [ESP-IDF](https://github.com/espressif/esp-idf) development fram The target names follow this format: `$ARCH-esp-espidf`, where `$ARCH` specifies the target processor architecture. The following targets are currently defined: -| Target name | Target CPU(s) | -|--------------------------------|-----------------------| -| `riscv32imc-esp-espidf` | [ESP32-C3](https://www.espressif.com/en/products/socs/esp32-c3) | - -The minimum supported ESP-IDF version is `v4.3`, though it is recommended to use the latest stable release if possible. +| Target name | Target CPU(s) | Minimum ESP-IDF version | +| ------------------------ | --------------------------------------------------------------- | ----------------------- | +| `riscv32imc-esp-espidf` | [ESP32-C2](https://www.espressif.com/en/products/socs/esp32-c2) | `v5.0` | +| `riscv32imc-esp-espidf` | [ESP32-C3](https://www.espressif.com/en/products/socs/esp32-c3) | `v4.3` | +| `riscv32imac-esp-espidf` | [ESP32-C6](https://www.espressif.com/en/products/socs/esp32-c6) | `v5.1` | +| `riscv32imac-esp-espidf` | [ESP32-H2](https://www.espressif.com/en/products/socs/esp32-h2) | `v5.1` | + +It is recommended to use the latest ESP-IDF stable release if possible. ## Building the target diff --git a/src/doc/rustc/src/platform-support/fuchsia.md b/src/doc/rustc/src/platform-support/fuchsia.md index 4d97b8c6c..f7cce35b1 100644 --- a/src/doc/rustc/src/platform-support/fuchsia.md +++ b/src/doc/rustc/src/platform-support/fuchsia.md @@ -681,12 +681,9 @@ local Rust source checkout: cd ${RUST_SRC_PATH} ``` -To run the Rust test suite on an emulated Fuchsia device, you must install the -Rust compiler locally. See "[Targeting Fuchsia with a compiler built from source](#targeting-fuchsia-with-a-compiler-built-from-source)" -for the steps to build locally. - -You'll also need to download a copy of the Fuchsia SDK. The current minimum -supported SDK version is [10.20221207.2.89][minimum_supported_sdk_version]. +To run the Rust test suite on an emulated Fuchsia device, you'll also need to +download a copy of the Fuchsia SDK. The current minimum supported SDK version is +[10.20221207.2.89][minimum_supported_sdk_version]. [minimum_supported_sdk_version]: https://chrome-infra-packages.appspot.com/p/fuchsia/sdk/core/linux-amd64/+/version:10.20221207.2.89 @@ -695,13 +692,13 @@ Fuchsia's test runner interacts with the Fuchsia emulator and is located at test environment with: ```sh -src/ci/docker/scripts/fuchsia-test-runner.py start - --rust ${RUST_SRC_PATH}/install - --sdk ${SDK_PATH} - --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia} +src/ci/docker/scripts/fuchsia-test-runner.py start \ + --rust-build ${RUST_SRC_PATH}/build \ + --sdk ${SDK_PATH} \ + --target {x86_64-unknown-fuchsia|aarch64-unknown-fuchsia} \ ``` -Where `${RUST_SRC_PATH}/install` is the `prefix` set in `config.toml` and +Where `${RUST_SRC_PATH}/build` is the `build-dir` set in `config.toml` and `${SDK_PATH}` is the path to the downloaded and unzipped SDK. Once our environment is started, we can run our tests using `x.py` as usual. The diff --git a/src/doc/rustc/src/platform-support/loongarch-linux.md b/src/doc/rustc/src/platform-support/loongarch-linux.md index 999e71f80..17e85590f 100644 --- a/src/doc/rustc/src/platform-support/loongarch-linux.md +++ b/src/doc/rustc/src/platform-support/loongarch-linux.md @@ -28,9 +28,9 @@ While the integer base ABI is implied by the machine field, the floating po ## Target maintainers -- [ZHAI Xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn` - [WANG Rui](https://github.com/heiher) `wangrui@loongson.cn` - [ZHAI Xiang](https://github.com/xiangzhai) `zhaixiang@loongson.cn` +- [ZHAI Xiaojuan](https://github.com/zhaixiaojuan) `zhaixiaojuan@loongson.cn` - [WANG Xuerui](https://github.com/xen0n) `git@xen0n.name` ## Requirements diff --git a/src/doc/rustc/src/platform-support/loongarch-none.md b/src/doc/rustc/src/platform-support/loongarch-none.md new file mode 100644 index 000000000..d0ae3425f --- /dev/null +++ b/src/doc/rustc/src/platform-support/loongarch-none.md @@ -0,0 +1,79 @@ +# `loongarch*-unknown-none*` + +**Tier: 3** + +Freestanding/bare-metal LoongArch64 binaries in ELF format: firmware, kernels, etc. + +| Target | Descriptions | +|------------------------------------|-------------------------------------------------------| +| loongarch64-unknown-none | LoongArch 64-bit, LP64D ABI (freestanding, hardfloat) | +| loongarch64-unknown-none-softfloat | LoongArch 64-bit, LP64S ABI (freestanding, softfloat) | + +## Target maintainers + +- [WANG Rui](https://github.com/heiher) `wangrui@loongson.cn` +- [WANG Xuerui](https://github.com/xen0n) `git@xen0n.name` + +## Requirements + +This target is cross-compiled. There is no support for `std`. There is no +default allocator, but it's possible to use `alloc` by supplying an allocator. + +This allows the generated code to run in environments, such as kernels, which +may need to avoid the use of such registers or which may have special considerations +about the use of such registers (e.g. saving and restoring them to avoid breaking +userspace code using the same registers). You can change code generation to use +additional CPU features via the `-C target-feature=` codegen options to rustc, or +via the `#[target_feature]` mechanism within Rust code. + +By default, code generated with this target should run on any `loongarch` +hardware; enabling additional target features may raise this baseline. + +Code generated with this target will use the `small` code model by default. +You can change this using the `-C code-model=` option to rustc. + +On `loongarch64-unknown-none*`, `extern "C"` uses the [standard calling +convention](https://loongson.github.io/LoongArch-Documentation/LoongArch-ELF-ABI-EN.html). + +This target generates binaries in the ELF format. Any alternate formats or +special considerations for binary layout will require linker options or linker +scripts. + +## Building the target + +You can build Rust with support for the target by adding it to the `target` +list in `config.toml`: + +```toml +[build] +build-stage = 1 +target = ["loongarch64-unknown-none"] +``` + +## Building Rust programs + +```text +# target flag may be used with any cargo or rustc command +cargo build --target loongarch64-unknown-none +``` + +## Testing + +As `loongarch64-unknown-none*` supports a variety of different environments and does +not support `std`, this target does not support running the Rust test suite. + +## Cross-compilation toolchains and C code + +If you want to compile C code along with Rust (such as for Rust crates with C +dependencies), you will need an appropriate `loongarch` toolchain. + +Rust *may* be able to use an `loongarch64-unknown-linux-gnu-` toolchain with +appropriate standalone flags to build for this toolchain (depending on the assumptions +of that toolchain, see below), or you may wish to use a separate +`loongarch64-unknown-none` toolchain. + +On some `loongarch` hosts that use ELF binaries, you *may* be able to use the host +C toolchain, if it does not introduce assumptions about the host environment +that don't match the expectations of a standalone environment. Otherwise, you +may need a separate toolchain for standalone/freestanding development, just as +when cross-compiling from a non-`loongarch` platform. diff --git a/src/doc/rustc/src/platform-support/netbsd.md b/src/doc/rustc/src/platform-support/netbsd.md new file mode 100644 index 000000000..23f4488de --- /dev/null +++ b/src/doc/rustc/src/platform-support/netbsd.md @@ -0,0 +1,108 @@ +# \*-unknown-netbsd + +**Tier: 3** + +[NetBSD] multi-platform 4.4BSD-based UNIX-like operating system. + +[NetBSD]: https://www.NetBSD.org/ + +The target names follow this format: `$ARCH-unknown-netbsd{-$SUFFIX}`, +where `$ARCH` specifies the target processor architecture and +`-$SUFFIX` (optional) might indicate the ABI. The following targets +are currently defined running NetBSD: + +| Target name | NetBSD Platform | +|--------------------------------|-----------------| +| `amd64-unknown-netbsd` | [amd64 / x86_64 systems](https://wiki.netbsd.org/ports/amd64/) | +| `armv7-unknown-netbsd-eabihf` | [32-bit ARMv7 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) | +| `armv6-unknown-netbsd-eabihf` | [32-bit ARMv6 systems with hard-float](https://wiki.netbsd.org/ports/evbarm/) | +| `aarch64-unknown-netbsd` | [64-bit ARM systems, little-endian](https://wiki.netbsd.org/ports/evbarm/) | +| `aarch64_be-unknown-netbsd` | [64-bit ARM systems, big-endian](https://wiki.netbsd.org/ports/evbarm/) | +| `i586-unknown-netbsd` | [32-bit i386, restricted to Pentium](https://wiki.netbsd.org/ports/i386/) | +| `i686-unknown-netbsd` | [32-bit i386 with SSE](https://wiki.netbsd.org/ports/i386/) | +| `mipsel-unknown-netbsd` | [32-bit mips, requires mips32 cpu support](https://wiki.netbsd.org/ports/evbmips/) | +| `powerpc-unknown-netbsd` | [Various 32-bit PowerPC systems, e.g. MacPPC](https://wiki.netbsd.org/ports/macppc/) | +| `riscv64gc-unknown-netbsd` | [64-bit RISC-V](https://wiki.netbsd.org/ports/riscv/) +| `sparc64-unknown-netbsd` | [Sun UltraSPARC systems](https://wiki.netbsd.org/ports/sparc64/) | + +All use the "native" `stdc++` library which goes along with the natively +supplied GNU C++ compiler for the given OS version. Many of the bootstraps +are built for NetBSD 9.x, although some exceptions exist (some +are built for NetBSD 8.x but also work on newer OS versions). + + +## Designated Developers + +- [@he32](https://github.com/he32), `he@NetBSD.org` +- [NetBSD/pkgsrc-wip's rust](https://github.com/NetBSD/pkgsrc-wip/blob/master/rust/Makefile) maintainer (see MAINTAINER variable). This package is part of "pkgsrc work-in-progress" and is used for deployment and testing of new versions of rust +- [NetBSD's pkgsrc lang/rust](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust) for the "proper" package in pkgsrc. +- [NetBSD's pkgsrc lang/rust-bin](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust-bin) which re-uses the bootstrap kit as a binary distribution and therefore avoids the rather protracted native build time of rust itself + +Fallback to pkgsrc-users@NetBSD.org, or fault reporting via NetBSD's +bug reporting system. + +## Requirements + +The `amd64-unknown-netbsd` artifacts is being distributed by the +rust project. + +The other targets are built by the designated developers (see above), +and the targets are initially cross-compiled, but many if not most +of them are also built natively as part of testing. + + +## Building + +The default build mode for the packages is a native build. + + +## Cross-compilation + +These targets can be cross-compiled, and we do that via the pkgsrc +package(s). + +Cross-compilation typically requires the "tools" and "dest" trees +resulting from a normal cross-build of NetBSD itself, ref. our main +build script, `build.sh`. + +See e.g. [do-cross.mk +Makefile](https://github.com/NetBSD/pkgsrc/tree/trunk/lang/rust/do-cross.mk) +for the Makefile used to cross-build all the above NetBSD targets +(except for the `amd64` target). + +The major option for the rust build is whether to build rust with +the LLVM rust carries in its distribution, or use the LLVM package +installed from pkgsrc. The `PKG_OPTIONS.rust` option is +`rust-internal-llvm`, ref. [the rust package's options.mk make +fragment](https://github.com/NetBSD/pkgsrc/blob/trunk/lang/rust/options.mk). +It defaults to being set for a few of the above platforms, for +various reasons (see comments), but is otherwise unset and therefore +indicates use of the pkgsrc LLVM. + + +## Testing + +The Rust testsuite could presumably be run natively. + +For the systems where the maintainer can build natively, the rust +compiler itself is re-built natively. This involves the rust compiler +being re-built with the newly self-built rust compiler, so excercises +the result quite extensively. + +Additionally, for some systems we build `librsvg`, and for the more +capable systems we build and test `firefox` (amd64, i386, aarch64). + + +## Building Rust programs + +Rust ships pre-compiled artifacts for the `amd64-unknown-netbsd` +target. + +For the other systems mentioned above, using the `pkgsrc` route is +probably the easiest, possibly via the `rust-bin` package to save +time, see the `RUST_TYPE` variable from the `rust.mk` Makefile +fragment. + +The pkgsrc rust package has a few files to assist with building +pkgsrc packages written in rust, ref. the `rust.mk` and `cargo.mk` +Makefile fragments in the `lang/rust` package. diff --git a/src/doc/rustc/src/platform-support/nto-qnx.md b/src/doc/rustc/src/platform-support/nto-qnx.md index 0d815c9b5..b376c4a84 100644 --- a/src/doc/rustc/src/platform-support/nto-qnx.md +++ b/src/doc/rustc/src/platform-support/nto-qnx.md @@ -164,18 +164,12 @@ export exclude_tests=' --exclude tests/run-make-fulldeps' env $build_env \ - ./x.py test -j 1 \ + ./x.py test \ $exclude_tests \ --stage 1 \ --target x86_64-pc-nto-qnx710 ``` -Currently, only one thread can be used when testing due to limitations in `libc::fork` and `libc::posix_spawnp`. -See [fork documentation](https://www.qnx.com/developers/docs/7.1/#com.qnx.doc.neutrino.lib_ref/topic/f/fork.html) -(error section) for more information. -This can be achieved by using the `-j 1` parameter in the `x.py` call. -This issue is being researched and we will try to allow parallelism in the future. - ## Building Rust programs Rust does not yet ship pre-compiled artifacts for this target. diff --git a/src/doc/rustdoc/src/SUMMARY.md b/src/doc/rustdoc/src/SUMMARY.md index b512135d9..12a8b2b8d 100644 --- a/src/doc/rustdoc/src/SUMMARY.md +++ b/src/doc/rustdoc/src/SUMMARY.md @@ -7,6 +7,7 @@ - [How to write documentation](how-to-write-documentation.md) - [What to include (and exclude)](write-documentation/what-to-include.md) - [The `#[doc]` attribute](write-documentation/the-doc-attribute.md) + - [Re-exports](write-documentation/re-exports.md) - [Linking to items by name](write-documentation/linking-to-items-by-name.md) - [Documentation tests](write-documentation/documentation-tests.md) - [Rustdoc-specific lints](lints.md) diff --git a/src/doc/rustdoc/src/how-to-read-rustdoc.md b/src/doc/rustdoc/src/how-to-read-rustdoc.md index ccd77fb17..9deb7009c 100644 --- a/src/doc/rustdoc/src/how-to-read-rustdoc.md +++ b/src/doc/rustdoc/src/how-to-read-rustdoc.md @@ -105,6 +105,16 @@ will match these queries: But it *does not* match `Result<Vec, u8>` or `Result<u8<Vec>>`. +Function signature searches also support arrays and slices. The explicit name +`primitive:slice<u8>` and `primitive:array<u8>` can be used to match a slice +or array of bytes, while square brackets `[u8]` will match either one. Empty +square brackets, `[]`, will match any slice regardless of what it contains. + +Paths are supported as well, you can look for `Vec::new` or `Option::Some` or +even `module::module_child::another_child::struct::field`. Whitespace characters +are considered the same as `::`, so if you write `Vec new`, it will be +considered the same as `Vec::new`. + ### Shortcuts Pressing `S` while focused elsewhere on the page will move focus to the diff --git a/src/doc/rustdoc/src/unstable-features.md b/src/doc/rustdoc/src/unstable-features.md index ae180439d..013b93e01 100644 --- a/src/doc/rustdoc/src/unstable-features.md +++ b/src/doc/rustdoc/src/unstable-features.md @@ -310,6 +310,8 @@ the source. ### `--show-type-layout`: add a section to each type's docs describing its memory layout +* Tracking issue: [#113248](https://github.com/rust-lang/rust/issues/113248) + Using this flag looks like this: ```bash diff --git a/src/doc/rustdoc/src/write-documentation/re-exports.md b/src/doc/rustdoc/src/write-documentation/re-exports.md new file mode 100644 index 000000000..593428b8a --- /dev/null +++ b/src/doc/rustdoc/src/write-documentation/re-exports.md @@ -0,0 +1,172 @@ +# Re-exports + +Let's start by explaining what are re-exports. To do so, we will use an example where we are +writing a library (named `lib`) with some types dispatched in sub-modules: + +```rust +pub mod sub_module1 { + pub struct Foo; +} +pub mod sub_module2 { + pub struct AnotherFoo; +} +``` + +Users can import them like this: + +```rust,ignore (inline) +use lib::sub_module1::Foo; +use lib::sub_module2::AnotherFoo; +``` + +But what if you want the types to be available directly at the crate root or if we don't want the +modules to be visible for users? That's where re-exports come in: + +```rust,ignore (inline) +// `sub_module1` and `sub_module2` are not visible outside. +mod sub_module1 { + pub struct Foo; +} +mod sub_module2 { + pub struct AnotherFoo; +} +// We re-export both types: +pub use crate::sub_module1::Foo; +pub use crate::sub_module2::AnotherFoo; +``` + +And now users will be able to do: + +```rust,ignore (inline) +use lib::{Foo, AnotherFoo}; +``` + +And since both `sub_module1` and `sub_module2` are private, users won't be able to import them. + +Now what's interesting is that the generated documentation for this crate will show both `Foo` and +`AnotherFoo` directly at the crate root, meaning they have been inlined. There are a few rules to +know whether or not a re-exported item will be inlined. + +## Inlining rules + +If a public item comes from a private module, it will be inlined: + +```rust,ignore (inline) +mod private_module { + pub struct Public; +} +pub mod public_mod { + // `Public` will inlined here since `private_module` is private. + pub use super::private_module::Public; +} +// `Public` will not be inlined here since `public_mod` is public. +pub use self::public_mod::Public; +``` + +Likewise, if an item inherits `#[doc(hidden)]` from any of its ancestors, it will be inlined: + +```rust,ignore (inline) +#[doc(hidden)] +pub mod public_mod { + pub struct Public; +} +// `Public` be inlined since its parent (`public_mod`) has `#[doc(hidden)]`. +pub use self::public_mod::Public; +``` + +If an item has `#[doc(hidden)]`, it won't be inlined (nor visible in the generated documentation): + +```rust,ignore (inline) +// This struct won't be visible. +#[doc(hidden)] +pub struct Hidden; + +// This re-export won't be visible. +pub use self::Hidden as InlinedHidden; +``` + +The same applies on re-exports themselves: if you have multiple re-exports and some of them have +`#[doc(hidden)]`, then these ones (and only these) own't appear in the documentation: + +```rust,ignore (inline) +mod private_mod { + /// First + pub struct InPrivate; +} + +/// Second +#[doc(hidden)] +pub use self::private_mod::InPrivate as Hidden; +/// Third +pub use self::Hidden as Visible; +``` + +In this case, `InPrivate` will be inlined as `Visible`. However, its documentation will be +`First Third` and not `First Second Third` because the re-export with `Second` as documentation has +`#[doc(hidden)]`, therefore, all its attributes are ignored. + +## Inlining with `#[doc(inline)]` + +You can use the `#[doc(inline)]` attribute if you want to force an item to be inlined: + +```rust,ignore (inline) +pub mod public_mod { + pub struct Public; +} +#[doc(inline)] +pub use self::public_mod::Public; +``` + +With this code, even though `public_mod::Public` is public and present in the documentation, the +`Public` type will be present both at the crate root and in the `public_mod` module. + +## Preventing inlining with `#[doc(no_inline)]` + +On the opposite of the `#[doc(inline)]` attribute, if you want to prevent an item from being +inlined, you can use `#[doc(no_inline)]`: + +```rust,ignore (inline) +mod private_mod { + pub struct Public; +} +#[doc(no_inline)] +pub use self::private_mod::Public; +``` + +In the generated documentation, you will see a re-export at the crate root and not the type +directly. + +## Attributes + +When an item is inlined, its doc comments and most of its attributes will be inlined along with it: + +```rust,ignore (inline) +mod private_mod { + /// First + #[cfg(a)] + pub struct InPrivate; + /// Second + #[cfg(b)] + pub use self::InPrivate as Second; +} + +/// Third +#[doc(inline)] +#[cfg(c)] +pub use self::private_mod::Second as Visible; +``` + +In this case, `Visible` will have as documentation `First Second Third` and will also have as `cfg`: +`#[cfg(a, b, c)]`. + +[Intra-doc links](./linking-to-items-by-name.md) are resolved relative to where the doc comment is +defined. + +There are a few attributes which are not inlined though: + * `#[doc(alias="")]` + * `#[doc(inline)]` + * `#[doc(no_inline)]` + * `#[doc(hidden)]` (because the re-export itself and its attributes are ignored). + +All other attributes are inherited when inlined, so that the documentation matches the behavior if +the inlined item was directly defined at the spot where it's shown. diff --git a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md index 8ecf05f0e..046d01854 100644 --- a/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md +++ b/src/doc/rustdoc/src/write-documentation/the-doc-attribute.md @@ -223,12 +223,18 @@ Now we'll have a `Re-exports` line, and `Bar` will not link to anywhere. One special case: In Rust 2018 and later, if you `pub use` one of your dependencies, `rustdoc` will not eagerly inline it as a module unless you add `#[doc(inline)]`. +If you want to know more about inlining rules, take a look at the +[`re-exports` chapter](./re-exports.md). + ### `hidden` <span id="dochidden"></span> Any item annotated with `#[doc(hidden)]` will not appear in the documentation, unless -the `strip-hidden` pass is removed. +the `strip-hidden` pass is removed. Re-exported items where one of its ancestors has +`#[doc(hidden)]` will be considered the same as private. + +You can find more information in the [`re-exports` chapter](./re-exports.md). ### `alias` diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md index adb73a7ee..b8aa64ba1 100644 --- a/src/doc/style-guide/src/README.md +++ b/src/doc/style-guide/src/README.md @@ -16,9 +16,21 @@ Rust code has similar formatting, less mental effort is required to comprehend a new project, lowering the barrier to entry for new developers. Thus, there are productivity benefits to using a formatting tool (such as -rustfmt), and even larger benefits by using a community-consistent formatting, -typically by using a formatting tool's default settings. +`rustfmt`), and even larger benefits by using a community-consistent +formatting, typically by using a formatting tool's default settings. +## The default Rust style + +The Rust Style Guide defines the default Rust style, and *recommends* that +developers and tools follow the default Rust style. Tools such as `rustfmt` use +the style guide as a reference for the default style. Everything in this style +guide, whether or not it uses language such as "must" or the imperative mood +such as "insert a space ..." or "break the line after ...", refers to the +default style. + +This should not be interpreted as forbidding developers from following a +non-default style, or forbidding tools from adding any particular configuration +options. ## Formatting conventions @@ -28,8 +40,47 @@ typically by using a formatting tool's default settings. * Each level of indentation must be four spaces (that is, all indentation outside of string literals and comments must be a multiple of four). * The maximum width for a line is 100 characters. -* A tool should be configurable for all three of these variables. +* A tool may choose to make some of these configurable. + +#### Block indent + +Prefer block indent over visual indent: + +```rust +// Block indent +a_function_call( + foo, + bar, +); + +// Visual indent +a_function_call(foo, + bar); +``` +This makes for smaller diffs (e.g., if `a_function_call` is renamed in the above +example) and less rightward drift. + +### Trailing commas + +Lists should have a trailing comma when followed by a newline: + +```rust +function_call( + argument, + another_argument, +); + +let array = [ + element, + another_element, + yet_another_element, +]; +``` + +This makes moving code (e.g., by copy and paste) easier, and makes diffs +smaller, as appending or removing items does not require modifying another line +to add or remove a comma. ### Blank lines @@ -48,11 +99,7 @@ fn bar() {} fn baz() {} ``` -Formatting tools should make the bounds on blank lines configurable: there -should be separate minimum and maximum numbers of newlines between both -statements and (top-level) items (i.e., four options). As described above, the -defaults for both statements and items should be minimum: 1, maximum: 2. - +Formatting tools may wish to make the bounds on blank lines configurable. ### [Module-level items](items.md) ### [Statements](statements.md) @@ -139,6 +186,11 @@ For attributes with argument lists, format like functions. ```rust #[repr(C)] #[foo(foo, bar)] +#[long_multi_line_attribute( + split, + across, + lines, +)] struct CRepr { #![repr(C)] x: f32, diff --git a/src/doc/style-guide/src/SUMMARY.md b/src/doc/style-guide/src/SUMMARY.md index 004692fa6..606485bfb 100644 --- a/src/doc/style-guide/src/SUMMARY.md +++ b/src/doc/style-guide/src/SUMMARY.md @@ -2,10 +2,11 @@ [Introduction](README.md) -- [Module-level items](items.md) +- [Items](items.md) - [Statements](statements.md) - [Expressions](expressions.md) -- [Types](types.md) -- [Non-formatting conventions](advice.md) +- [Types and Bounds](types.md) +- [Other style advice](advice.md) - [`Cargo.toml` conventions](cargo.md) -- [Principles used for deciding these guidelines](principles.md) +- [Guiding principles and rationale](principles.md) +- [Nightly-only syntax](nightly.md) diff --git a/src/doc/style-guide/src/advice.md b/src/doc/style-guide/src/advice.md index ab4b92b0a..9a617be50 100644 --- a/src/doc/style-guide/src/advice.md +++ b/src/doc/style-guide/src/advice.md @@ -25,9 +25,9 @@ if y { * Local variables shall be `snake_case`, * Macro names shall be `snake_case`, * Constants (`const`s and immutable `static`s) shall be `SCREAMING_SNAKE_CASE`. - * When a name is forbidden because it is a reserved word (e.g., `crate`), use a - trailing underscore to make the name legal (e.g., `crate_`), or use raw - identifiers if possible. + * When a name is forbidden because it is a reserved word (such as `crate`), + either use a raw identifier (`r#crate`) or use a trailing underscore + (`crate_`). Don't misspell the word (`krate`). ### Modules diff --git a/src/doc/style-guide/src/cargo.md b/src/doc/style-guide/src/cargo.md index 13b96ca8c..d3b67ae45 100644 --- a/src/doc/style-guide/src/cargo.md +++ b/src/doc/style-guide/src/cargo.md @@ -1,4 +1,4 @@ -# Cargo.toml conventions +# `Cargo.toml` conventions ## Formatting conventions @@ -25,16 +25,17 @@ not indent any key names; start all key names at the start of a line. Use multi-line strings (rather than newline escape sequences) for any string values that include multiple lines, such as the crate description. -For array values, such as a list of authors, put the entire list on the same +For array values, such as a list of features, put the entire list on the same line as the key, if it fits. Otherwise, use block indentation: put a newline after the opening square bracket, indent each item by one indentation level, put a comma after each item (including the last), and put the closing square bracket at the start of a line by itself after the last item. ```rust -authors = [ - "A Uthor <a.uthor@example.org>", - "Another Author <author@example.net>", +some_feature = [ + "another_feature", + "yet_another_feature", + "some_dependency?/some_feature", ] ``` @@ -54,11 +55,11 @@ version = "4.5.6" ## Metadata conventions -The authors list should consist of strings that each contain an author name -followed by an email address in angle brackets: `Full Name <email@address>`. -It should not contain bare email addresses, or names without email addresses. -(The authors list may also include a mailing list address without an associated -name.) +The authors list, if present, should consist of strings that each contain an +author name followed by an email address in angle brackets: `Full Name +<email@address>`. It should not contain bare email addresses, or names without +email addresses. (The authors list may also include a mailing list address +without an associated name.) The license field must contain a valid [SPDX expression](https://spdx.org/spdx-specification-21-web-version#h.jxpfx0ykyb60), diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index 96f66c89c..143161da6 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -288,14 +288,16 @@ and other assignment operators such as `+=` or `*=`). For comparison operators, because for `T op U`, `&T op &U` is also implemented: if you have `t: &T`, and `u: U`, prefer `*t op u` to `t op &u`. In general, -within expressions, prefer dereferencing to taking references. +within expressions, prefer dereferencing to taking references, unless necessary +(e.g. to avoid an unnecessarily expensive operation). Use parentheses liberally, do not necessarily elide them due to precedence. Tools should not automatically insert or remove parentheses. Do not use spaces to indicate precedence. -If line-breaking, put the operator on a new line and block indent. Put each -sub-expression on its own line. E.g., +If line-breaking, block-indent each subsequent line. For assignment operators, +break after the operator; for all other operators, put the operator on the +subsequent line. Put each sub-expression on its own line: ```rust foo_bar @@ -690,7 +692,7 @@ Where it is possible to use a block form on the right-hand side and avoid breaking the left-hand side, do that. E.g. ```rust - // Assuming the following line does done fit in the max width + // Assuming the following line does not fit in the max width a_very_long_pattern | another_pattern => ALongStructName { ... }, @@ -751,9 +753,9 @@ not put the `if` clause on a newline. E.g., } ``` -If every clause in a pattern is *small*, but does not fit on one line, then the -pattern may be formatted across multiple lines with as many clauses per line as -possible. Again break before a `|`: +If every clause in a pattern is *small*, but the whole pattern does not fit on +one line, then the pattern may be formatted across multiple lines with as many +clauses per line as possible. Again break before a `|`: ```rust foo | bar | baz @@ -762,17 +764,18 @@ possible. Again break before a `|`: } ``` -We define a pattern clause to be *small* if it matches the following grammar: +We define a pattern clause to be *small* if it fits on a single line and +matches "small" in the following grammar: ``` -[small, ntp]: - - single token - - `&[single-line, ntp]` +small: + - small_no_tuple + - unary tuple constructor: `(` small_no_tuple `,` `)` + - `&` small -[small]: - - `[small, ntp]` - - unary tuple constructor `([small, ntp])` - - `&[small]` +small_no_tuple: + - single token + - `&` small_no_tuple ``` E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not. diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index 283597535..1e0e60248 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -1,5 +1,10 @@ ## Items +Items consist of the set of things permitted at the top level of a module. +However, Rust also allows some items to appear within some other types of +items, such as within a function. The same formatting conventions apply whether +an item appears at module level or within another item. + `extern crate` statements must be first in a file. They must be ordered alphabetically. @@ -15,8 +20,8 @@ Tools should make the above ordering optional. ### Function definitions -In Rust, one finds functions by searching for `fn [function-name]`; It's -important that you style your code so that it's very searchable in this way. +In Rust, people often find functions by searching for `fn [function-name]`, so +the formatting of function definitions shold enable this. The proper ordering and spacing is: @@ -63,8 +68,9 @@ let y = (11, 22, 33); In the declaration, put each variant on its own line, block indented. -Format each variant accordingly as either a struct, tuple struct, or identifier, -which doesn't require special formatting (but without the `struct` keyword. +Format each variant accordingly as either a struct (but without the `struct` +keyword), a tuple struct, or an identifier (which doesn't require special +formatting): ```rust enum FooBar { @@ -139,7 +145,7 @@ union Foo { Put the whole struct on one line if possible. Types in the parentheses should be separated by a comma and space with no trailing comma. No spaces around the -parentheses or semi-colon: +parentheses or semicolon: ```rust pub struct Foo(String, u8); @@ -230,7 +236,7 @@ impl Bar `extern crate foo;` -Use spaces around keywords, no spaces around the semi-colon. +Use spaces around keywords, no spaces around the semicolon. ### Modules @@ -245,7 +251,7 @@ mod foo; ``` Use spaces around keywords and before the opening brace, no spaces around the -semi-colon. +semicolon. ### macro\_rules! @@ -478,8 +484,8 @@ foo::{ A *group* of imports is a set of imports on the same or sequential lines. One or more blank lines or other items (e.g., a function) separate groups of imports. -Within a group of imports, imports must be sorted ascii-betically. Groups of -imports must not be merged or re-ordered. +Within a group of imports, imports must be sorted ASCIIbetically (uppercase +before lowercase). Groups of imports must not be merged or re-ordered. E.g., input: @@ -505,13 +511,9 @@ use b; Because of `macro_use`, attributes must also start a new group and prevent re-ordering. -Note that tools which only have access to syntax (such as Rustfmt) cannot tell -which imports are from an external crate or the std lib, etc. - - #### Ordering list import -Names in a list import must be sorted ascii-betically, but with `self` and +Names in a list import must be sorted ASCIIbetically, but with `self` and `super` first, and groups and glob imports last. This applies recursively. For example, `a::*` comes before `b::a` but `a::b` comes before `a::*`. E.g., `use foo::bar::{a, b::c, b::d, b::d::{x, y, z}, b::{self, r, s}};`. diff --git a/src/doc/style-guide/src/nightly.md b/src/doc/style-guide/src/nightly.md new file mode 100644 index 000000000..031811b0e --- /dev/null +++ b/src/doc/style-guide/src/nightly.md @@ -0,0 +1,5 @@ +This chapter documents style and formatting for nightly-only syntax. The rest of the style guide documents style for stable Rust syntax; nightly syntax only appears in this chapter. Each section here includes the name of the feature gate, so that searches (e.g. `git grep`) for a nightly feature in the Rust repository also turn up the style guide section. + +Style and formatting for nightly-only syntax should be removed from this chapter and integrated into the appropriate sections of the style guide at the time of stabilization. + +There is no guarantee of the stability of this chapter in contrast to the rest of the style guide. Refer to the style team policy for nightly formatting procedure regarding breaking changes to this chapter. diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md index 2d203f264..d548693e3 100644 --- a/src/doc/style-guide/src/principles.md +++ b/src/doc/style-guide/src/principles.md @@ -1,7 +1,7 @@ # Guiding principles and rationale -When deciding on style guidelines, the style team tried to be guided by the -following principles (in rough priority order): +When deciding on style guidelines, the style team follows these guiding +principles (in rough priority order): * readability - scan-ability @@ -19,35 +19,11 @@ following principles (in rough priority order): * specifics - compatibility with version control practices - preserving diffs, merge-friendliness, etc. - - preventing right-ward drift + - preventing rightward drift - minimising vertical space * application - ease of manual application - - ease of implementation (in Rustfmt, and in other tools/editors/code generators) + - ease of implementation (in `rustfmt`, and in other tools/editors/code generators) - internal consistency - simplicity of formatting rules - - -## Overarching guidelines - -Prefer block indent over visual indent. E.g., - -```rust -// Block indent -a_function_call( - foo, - bar, -); - -// Visual indent -a_function_call(foo, - bar); -``` - -This makes for smaller diffs (e.g., if `a_function_call` is renamed in the above -example) and less rightward drift. - -Lists should have a trailing comma when followed by a newline, see the block -indent example above. This choice makes moving code (e.g., by copy and paste) -easier and makes smaller diffs. diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md index 671e6d31a..a5cd6da10 100644 --- a/src/doc/style-guide/src/statements.md +++ b/src/doc/style-guide/src/statements.md @@ -1,7 +1,9 @@ +## Statements + ### Let statements There should be spaces after the `:` and on both sides of the `=` (if they are -present). No space before the semi-colon. +present). No space before the semicolon. ```rust // A comment. @@ -101,22 +103,69 @@ let Foo { #### else blocks (let-else statements) -If a let statement contains an `else` component, also known as a let-else statement, -then the `else` component should be formatted according to the same rules as the `else` block -in [control flow expressions (i.e. if-else, and if-let-else expressions)](./expressions.md#control-flow-expressions). -Apply the same formatting rules to the components preceding -the `else` block (i.e. the `let pattern: Type = initializer_expr ...` portion) -as described [above](#let-statements) +A let statement can contain an `else` component, making it a let-else statement. +In this case, always apply the same formatting rules to the components preceding +the `else` block (i.e. the `let pattern: Type = initializer_expr` portion) +as described [for other let statements](#let-statements). + +The entire let-else statement may be formatted on a single line if all the +following are true: -Similarly to if-else expressions, if the initializer -expression is multi-lined, then the `else` keyword and opening brace of the block (i.e. `else {`) -should be put on the same line as the end of the initializer -expression with a preceding space if all the following are true: +* the entire statement is *short* +* the `else` block contains only a single-line expression and no statements +* the `else` block contains no comments +* the let statement components preceding the `else` block can be formatted on a single line + +```rust +let Some(1) = opt else { return }; +``` + +Formatters may allow users to configure the value of the threshold +used to determine whether a let-else statement is *short*. + +Otherwise, the let-else statement requires some line breaks. + +If breaking a let-else statement across multiple lines, never break between the +`else` and the `{`, and always break before the `}`. + +If the let statement components preceding the `else` can be formatted on a +single line, but the let-else does not qualify to be placed entirely on a +single line, put the `else {` on the same line as the initializer expression, +with a space between them, then break the line after the `{`. Indent the +closing `}` to match the `let`, and indent the contained block one step +further. + +```rust +let Some(1) = opt else { + return; +}; + +let Some(1) = opt else { + // nope + return +}; +``` + +If the let statement components preceding the `else` can be formatted on a +single line, but the `else {` does not fit on the same line, break the line +before the `else`. + +```rust + let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name + else { + return; + }; +``` + +If the initializer expression is multi-line, the `else` keyword and opening +brace of the block (i.e. `else {`) should be put on the same line as the end of +the initializer expression, with a space between them, if and only if all the +following are true: * The initializer expression ends with one or more closing parentheses, square brackets, and/or braces * There is nothing else on that line -* That line is not indented beyond the indent of the first line containing the `let` keyword +* That line has the same indentation level as the initial `let` keyword. For example: @@ -133,7 +182,9 @@ let Some(x) = y.foo( } ``` -Otherwise, the `else` keyword and opening brace should be placed on the next line after the end of the initializer expression, and should not be indented (the `else` keyword should be aligned with the `let` keyword). +Otherwise, the `else` keyword and opening brace should be placed on the next +line after the end of the initializer expression, and the `else` keyword should +have the same indentation level as the `let` keyword. For example: @@ -153,48 +204,40 @@ fn main() { return }; - let Some(x) = some_really_really_really_really_really_really_really_really_really_long_name + let Some(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) = + bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb else { return; }; - let Some(aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa) = - bbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbbb + let LongStructName(AnotherStruct { + multi, + line, + pattern, + }) = slice.as_ref() else { return; }; -} -``` - -##### Single line let-else statements - -The entire let-else statement may be formatted on a single line if all the following are true: - -* the entire statement is *short* -* the `else` block contains a single-line expression and no statements -* the `else` block contains no comments -* the let statement components preceding the `else` block can be formatted on a single line - -```rust -let Some(1) = opt else { return }; - -let Some(1) = opt else { - return; -}; -let Some(1) = opt else { - // nope - return -}; + let LongStructName(AnotherStruct { + multi, + line, + pattern, + }) = multi_line_function_call( + arg1, + arg2, + arg3, + arg4, + ) else { + return; + }; +} ``` -Formatters may allow users to configure the value of the threshold -used to determine whether a let-else statement is *short*. - ### Macros in statement position A macro use in statement position should use parentheses or square brackets as -delimiters and should be terminated with a semi-colon. There should be no spaces +delimiters and should be terminated with a semicolon. There should be no spaces between the name, `!`, the delimiters, or the `;`. ```rust @@ -205,13 +248,13 @@ a_macro!(...); ### Expressions in statement position -There should be no space between the expression and the semi-colon. +There should be no space between the expression and the semicolon. ``` <expr>; ``` -All expressions in statement position should be terminated with a semi-colon, +All expressions in statement position should be terminated with a semicolon, unless they end with a block or are used as the value for a block. E.g., @@ -229,7 +272,7 @@ loop { } ``` -Use a semi-colon where an expression has void type, even if it could be +Use a semicolon where an expression has void type, even if it could be propagated. E.g., ```rust diff --git a/src/doc/unstable-book/src/compiler-flags/sanitizer.md b/src/doc/unstable-book/src/compiler-flags/sanitizer.md index aa776daf0..49389b28c 100644 --- a/src/doc/unstable-book/src/compiler-flags/sanitizer.md +++ b/src/doc/unstable-book/src/compiler-flags/sanitizer.md @@ -21,7 +21,8 @@ This feature allows for use of one of following sanitizers: * [MemorySanitizer](#memorysanitizer) a detector of uninitialized reads. * [MemTagSanitizer](#memtagsanitizer) fast memory error detector based on Armv8.5-A Memory Tagging Extension. -* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection. +* [SafeStack](#safestack) provides backward-edge control flow protection by separating the stack into safe and unsafe regions. +* [ShadowCallStack](#shadowcallstack) provides backward-edge control flow protection (aarch64 only). * [ThreadSanitizer](#threadsanitizer) a fast data race detector. To enable a sanitizer compile with `-Zsanitizer=address`,`-Zsanitizer=cfi`, @@ -712,6 +713,16 @@ To enable this target feature compile with `-C target-feature="+mte"`. See the [LLVM MemTagSanitizer documentation][llvm-memtag] for more details. +# SafeStack + +SafeStack provides backward edge control flow protection by separating the stack into data which is only accessed safely (the safe stack) and all other data (the unsafe stack). + +SafeStack can be enabled with the `-Zsanitizer=safestack` option and is supported on the following targets: + +* `x86_64-unknown-linux-gnu` + +See the [Clang SafeStack documentation][clang-safestack] 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. @@ -828,6 +839,7 @@ Sanitizers produce symbolized stacktraces when llvm-symbolizer binary is in `PAT [clang-kcfi]: https://clang.llvm.org/docs/ControlFlowIntegrity.html#fsanitize-kcfi [clang-lsan]: https://clang.llvm.org/docs/LeakSanitizer.html [clang-msan]: https://clang.llvm.org/docs/MemorySanitizer.html +[clang-safestack]: https://clang.llvm.org/docs/SafeStack.html [clang-scs]: https://clang.llvm.org/docs/ShadowCallStack.html [clang-tsan]: https://clang.llvm.org/docs/ThreadSanitizer.html [linux-kasan]: https://www.kernel.org/doc/html/latest/dev-tools/kasan.html diff --git a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md index 532cb9eea..c634dc50d 100644 --- a/src/doc/unstable-book/src/language-features/asm-experimental-arch.md +++ b/src/doc/unstable-book/src/language-features/asm-experimental-arch.md @@ -17,7 +17,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect - AVR - MSP430 - M68k -- LoongArch - s390x ## Register classes @@ -47,8 +46,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | M68k | `reg` | `d[0-7]`, `a[0-7]` | `r` | | M68k | `reg_data` | `d[0-7]` | `d` | | M68k | `reg_addr` | `a[0-3]` | `a` | -| LoongArch | `reg` | `$r1`, `$r[4-20]`, `$r[23,30]` | `r` | -| LoongArch | `freg` | `$f[0-31]` | `f` | | s390x | `reg` | `r[0-10]`, `r[12-14]` | `r` | | s390x | `freg` | `f[0-15]` | `f` | @@ -82,8 +79,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | MSP430 | `reg` | None | `i8`, `i16` | | M68k | `reg`, `reg_addr` | None | `i16`, `i32` | | M68k | `reg_data` | None | `i8`, `i16`, `i32` | -| LoongArch64 | `reg` | None | `i8`, `i16`, `i32`, `i64`, `f32`, `f64` | -| LoongArch64 | `freg` | None | `f32`, `f64` | | s390x | `reg` | None | `i8`, `i16`, `i32`, `i64` | | s390x | `freg` | None | `f32`, `f64` | @@ -107,10 +102,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | M68k | `a5` | `bp` | | M68k | `a6` | `fp` | | M68k | `a7` | `sp`, `usp`, `ssp`, `isp` | -| LoongArch | `$r0` | `zero` | -| LoongArch | `$r2` | `tp` | -| LoongArch | `$r3` | `sp` | -| LoongArch | `$r22` | `fp` | > **Notes**: > - TI does not mandate a frame pointer for MSP430, but toolchains are allowed @@ -121,7 +112,7 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | Architecture | Unsupported register | Reason | | ------------ | --------------------------------------- | ----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- | | All | `sp`, `r15` (s390x) | The stack pointer must be restored to its original value at the end of an asm code block. | -| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `$fp` (LoongArch), `r11` (s390x) | The frame pointer cannot be used as an input or output. | +| All | `fr` (Hexagon), `$fp` (MIPS), `Y` (AVR), `r4` (MSP430), `a6` (M68k), `r11` (s390x) | The frame pointer cannot be used as an input or output. | | All | `r19` (Hexagon) | This is used internally by LLVM as a "base pointer" for functions with complex stack frames. | | MIPS | `$0` or `$zero` | This is a constant zero register which can't be modified. | | MIPS | `$1` or `$at` | Reserved for assembler. | @@ -132,10 +123,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | AVR | `r0`, `r1`, `r1r0` | Due 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. | |MSP430 | `r0`, `r2`, `r3` | These are the program counter, status register, and constant generator respectively. Neither the status register nor constant generator can be written to. | | M68k | `a4`, `a5` | Used internally by LLVM for the base pointer and global base pointer. | -| LoongArch | `$r0` or `$zero` | This is a constant zero register which can't be modified. | -| LoongArch | `$r2` or `$tp` | This is reserved for TLS. | -| LoongArch | `$r21` | This is reserved by the ABI. | -| LoongArch | `$r31` or `$s8` | This is used internally by LLVM. | ## Template modifiers @@ -150,8 +137,6 @@ This feature tracks `asm!` and `global_asm!` support for the following architect | PowerPC | `reg` | None | `0` | None | | PowerPC | `reg_nonzero` | None | `3` | `b` | | PowerPC | `freg` | None | `0` | None | -| LoongArch | `reg` | None | `$r2` | None | -| LoongArch | `freg` | None | `$f0` | None | | s390x | `reg` | None | `%r0` | None | | s390x | `freg` | None | `%f0` | None | diff --git a/src/doc/unstable-book/src/language-features/const-eval-limit.md b/src/doc/unstable-book/src/language-features/const-eval-limit.md deleted file mode 100644 index df68e83bc..000000000 --- a/src/doc/unstable-book/src/language-features/const-eval-limit.md +++ /dev/null @@ -1,7 +0,0 @@ -# `const_eval_limit` - -The tracking issue for this feature is: [#67217] - -[#67217]: https://github.com/rust-lang/rust/issues/67217 - -The `const_eval_limit` allows someone to limit the evaluation steps the CTFE undertakes to evaluate a `const fn`. diff --git a/src/doc/unstable-book/src/language-features/lang-items.md b/src/doc/unstable-book/src/language-features/lang-items.md index 6adb3506e..f4bc18bc7 100644 --- a/src/doc/unstable-book/src/language-features/lang-items.md +++ b/src/doc/unstable-book/src/language-features/lang-items.md @@ -11,8 +11,8 @@ 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` +For example, `Box` pointers require a lang item for allocation. +A freestanding program that uses the `Box` sugar for dynamic allocations via `malloc` and `free`: ```rust,ignore (libc-is-finicky) @@ -48,9 +48,10 @@ unsafe fn allocate(size: usize, _align: usize) -> *mut u8 { p } -#[lang = "box_free"] -unsafe fn box_free<T: ?Sized>(ptr: *mut T) { - libc::free(ptr as *mut libc::c_void) +impl<T> Drop for Box<T> { + fn drop(&mut self) { + libc::free(self.0.0.0 as *mut libc::c_void) + } } #[start] @@ -84,8 +85,8 @@ Other features provided by lang items include: `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 +`Box` then there is no need to define a function for `exchange_malloc`. +`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 @@ -250,7 +251,6 @@ the source code. - 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` |