diff --git a/compiler/rustc_driver_impl/src/session_diagnostics.rs b/compiler/rustc_driver_impl/src/session_diagnostics.rs index f800c3f6b9d0d..c0d1c77c16f26 100644 --- a/compiler/rustc_driver_impl/src/session_diagnostics.rs +++ b/compiler/rustc_driver_impl/src/session_diagnostics.rs @@ -52,6 +52,9 @@ pub(crate) struct RlinkCorruptFile<'a> { #[derive(Diagnostic)] #[diag("the compiler unexpectedly panicked. This is a bug")] +#[note("we would appreciate a bug report with a minimal reproduction at the URL below")] +#[note("set `RUST_BACKTRACE=1` environment variable to display a backtrace")] +#[note("try running `cargo clean` and rebuilding; transient failures do sometimes occur")] pub(crate) struct Ice; #[derive(Diagnostic)] diff --git a/compiler/rustc_error_codes/src/error_codes/E0035.md b/compiler/rustc_error_codes/src/error_codes/E0035.md new file mode 100644 index 0000000000000..e340759f38f81 --- /dev/null +++ b/compiler/rustc_error_codes/src/error_codes/E0035.md @@ -0,0 +1,50 @@ +The type parameter list on a method call was provided, but the method in +question doesn't accept type parameters directly at the call site. + +Note: E0035 was previously used for "argument count mismatch" but has since been +merged into E0087/E0089. The most common way to encounter a related message +today is when using turbofish syntax on a **trait method** that does not accept +type parameters at the call site. + +## Turbofish on trait methods + +A common mistake is trying to specify the output type of a trait method like +`into()` using turbofish syntax: + +```rust,ignore +let x: u32 = y.into::(); // This does not work +``` + +Trait methods do not accept turbofish syntax because the type is resolved by +the trait bound, not by the call site. Attempting this produces an error +because `Into::into` takes no type parameters. + +The correct approach is to annotate the **variable binding** with the expected +type, which lets the compiler infer the correct trait implementation: + +``` +let y: i32 = 42; +let x: u32 = y.into(); // ok: compiler infers `Into` from the type of `x` +``` + +Alternatively, use the fully-qualified syntax which does allow you to name the +trait explicitly: + +``` +let y: i32 = 42; +let x = Into::::into(y); // ok: fully-qualified call names the trait +``` + +When the type must be specified at the call site for another method, use a +type annotation on the variable instead of turbofish: + +``` +// Instead of: let x = some_value.method::() +// Write: let x: Type = some_value.method() +let x: Vec = "hello".chars().rev().collect(); // ok +``` + +See also [E0283] for the "type annotations required" error that often precedes +the turbofish attempt. + +[E0283]: https://doc.rust-lang.org/error_codes/E0283.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0038.md b/compiler/rustc_error_codes/src/error_codes/E0038.md index 4b06395897a87..8ccd95144af4d 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0038.md +++ b/compiler/rustc_error_codes/src/error_codes/E0038.md @@ -4,6 +4,12 @@ Rust, trait object types were written as plain `Trait` (just the name of the trait, written in type positions) but this was a bit too confusing, so we now write `dyn Trait`. +**What is a trait object?** A trait object (`dyn Trait`) is a way to store or +pass values of *different* concrete types behind a single pointer, as long as +all those types implement `Trait`. For example, `Box` can hold a +`Dog` or a `Cat` — the compiler does not know which at compile time, so it uses +dynamic dispatch (a vtable pointer at runtime) to call the right method. + Some traits are not allowed to be used as trait object types. The traits that are allowed to be used as trait object types are called "dyn-compatible"[^1] traits. Attempting to use a trait object type for a trait that is not @@ -31,6 +37,41 @@ aspects. [^1]: Formerly known as "object-safe". +## Common mistake: using a trait as a direct parameter type + +A frequent trigger of E0038 is writing a trait name where a concrete type or +generic is expected: + +```compile_fail,E0038 +use std::thread; + +fn named_thread(name: Into, f: impl FnOnce()) { +// ^^^^^^^^^^^^ `Into` is not a concrete type; +// this becomes `dyn Into` which +// is not dyn-compatible because `Into` +// has a method that returns `Self` +} +``` + +The fix is to use a **generic type parameter** or **`impl Trait`** syntax: + +``` +use std::thread; + +// Option 1: generic type parameter +fn named_thread_generic>(name: S, f: impl FnOnce()) { + // ... +} + +// Option 2: impl Trait (equivalent, more concise) +fn named_thread(name: impl Into, f: impl FnOnce()) { + // ... +} +``` + +Both forms tell the compiler "accept any concrete type that implements +`Into`", without creating a trait object. + ### The trait requires `Self: Sized` Traits that are declared as `Trait: Sized` or which otherwise inherit a diff --git a/compiler/rustc_error_codes/src/error_codes/E0117.md b/compiler/rustc_error_codes/src/error_codes/E0117.md index 0544667cccaea..b9048c6f6283b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0117.md +++ b/compiler/rustc_error_codes/src/error_codes/E0117.md @@ -14,26 +14,48 @@ trait defined in another crate) where - all of the parameters being passed to the trait (if there are any) are also foreign. -To avoid this kind of error, ensure that at least one local type is referenced -by the `impl`: +## Understanding "local" vs "foreign" types +- A **local type** is any type defined in the **current** crate. +- A **foreign type** is any type defined in **another** crate (including `std`, + `core`, and any dependency). + +The orphan rule requires that **at least one** type mentioned in the `impl` is +local. This prevents two crates from each providing conflicting implementations +for the same trait+type combination, which would cause ambiguity. + +### The three cases that trigger E0117 + +**Case 1: Foreign trait + foreign type** + +```compile_fail,E0117 +// `Display` is foreign (from `std`), `Vec` is foreign (from `std`) +use std::fmt; +impl fmt::Display for Vec {} // error: both trait and type are foreign ``` -pub struct Foo; // you define your type in your crate -impl Drop for Foo { // and you can implement the trait on it! - // code of trait implementation here -# fn drop(&mut self) { } -} +**Case 2: Foreign trait + all-foreign type parameters** -impl From for i32 { // or you use a type from your crate as - // a type parameter - fn from(i: Foo) -> i32 { - 0 - } +```compile_fail,E0117 +// `From` is foreign, and both `String` and `Vec` are foreign +impl From> for String {} // error: no local type involved +``` + +**Case 3: Foreign trait on a foreign generic type, even with a local parameter** + +```compile_fail,E0117 +// `Iterator` is foreign, `Vec` uses Vec (foreign) as the outer type. +// A local type as a *type parameter* of a foreign generic type is not enough. +struct MyLocal; +impl Iterator for Vec { // error: the "implementing type" Vec<_> is foreign + type Item = MyLocal; + fn next(&mut self) -> Option { None } } ``` -Alternatively, define a trait locally and implement that instead: +## How to fix E0117 + +**Fix 1:** Define the trait locally and implement that instead: ``` trait Bar { @@ -45,6 +67,38 @@ impl Bar for u32 { } ``` +**Fix 2:** Wrap the foreign type in a local newtype and implement the trait on +the wrapper: + +``` +use std::fmt; + +// Wrap the foreign type in a local struct +struct MyVec(Vec); + +impl fmt::Display for MyVec { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "{:?}", self.0) + } +} +``` + +**Fix 3:** Use a local type as the `Self` type with a foreign trait: + +``` +pub struct Foo; // local type + +impl Drop for Foo { // ok: Foo is local + fn drop(&mut self) { } +} + +impl From for i32 { // ok: Foo is local (as a type parameter) + fn from(i: Foo) -> i32 { + 0 + } +} +``` + For information on the design of the orphan rules, see [RFC 1023]. [RFC 1023]: https://github.com/rust-lang/rfcs/blob/master/text/1023-rebalancing-coherence.md diff --git a/compiler/rustc_error_codes/src/error_codes/E0277.md b/compiler/rustc_error_codes/src/error_codes/E0277.md index 5f05b59d5a6d4..e7b317f7ab7e6 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0277.md +++ b/compiler/rustc_error_codes/src/error_codes/E0277.md @@ -85,3 +85,100 @@ fn main() { Rust only looks at the signature of the called function, as such it must already specify all requirements that will be used for every type parameter. + +## E0277 with the `?` operator — missing `From` implementation + +A common and confusing case of E0277 occurs when using the `?` operator for +error propagation. When `?` is used inside a function, it **implicitly converts** +the error type using the `From` trait. If the conversion is not implemented, you +will see an error like: + +``` +the trait `From` is not implemented for `Error2` +``` + +The connection to `?` is not always obvious. Here is an example: + +```compile_fail,E0277 +use std::num::ParseIntError; +use std::fmt; + +#[derive(Debug)] +struct MyError(String); + +impl fmt::Display for MyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "my error: {}", self.0) + } +} + +// This function returns `MyError`, but `?` tries to convert `ParseIntError` +// into `MyError` using `From` — which isn't implemented. +fn parse_number(s: &str) -> Result { + let n = s.parse::()?; // error: `From` not implemented for `MyError` + Ok(n) +} +``` + +The `?` operator expands roughly to: + +```rust,ignore +let n = match s.parse::() { + Ok(val) => val, + Err(e) => return Err(MyError::from(e)), // requires From for MyError +}; +``` + +**Fix option 1:** Implement `From` for `MyError`: + +``` +use std::num::ParseIntError; +use std::fmt; + +#[derive(Debug)] +struct MyError(String); + +impl fmt::Display for MyError { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + write!(f, "my error: {}", self.0) + } +} + +impl From for MyError { + fn from(e: ParseIntError) -> MyError { + MyError(e.to_string()) + } +} + +fn parse_number(s: &str) -> Result { + let n = s.parse::()?; // ok: From is now implemented + Ok(n) +} +``` + +**Fix option 2:** Convert the error explicitly without `?`: + +``` +use std::num::ParseIntError; + +#[derive(Debug)] +struct MyError(String); + +fn parse_number(s: &str) -> Result { + let n = s.parse::().map_err(|e| MyError(e.to_string()))?; + Ok(n) +} +``` + +**Fix option 3:** Use a boxed error type that accepts any error implementing +`std::error::Error`: + +``` +fn parse_number(s: &str) -> Result> { + let n = s.parse::()?; // ok: Box implements From for any E: Error + Ok(n) +} +``` + +When you see E0277 involving `From`, look for `?` operators in the function +body — the `?` is almost certainly the source of the implicit conversion attempt. diff --git a/compiler/rustc_error_codes/src/error_codes/E0283.md b/compiler/rustc_error_codes/src/error_codes/E0283.md index b2f0ede6a0b68..fa11c6b778a13 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0283.md +++ b/compiler/rustc_error_codes/src/error_codes/E0283.md @@ -71,3 +71,44 @@ impl Into for Foo { let foo = Foo; let bar: u32 = Into::::into(foo) * 1u32; ``` + +## Annotating `into()` — turbofish does not work on trait methods + +A common follow-up mistake when seeing E0283 on `into()` is to try to use +turbofish syntax to specify the type: + +```rust,ignore +let x: u32 = y.into::(); // error[E0035]: does not take type parameters +``` + +This does **not** work. `Into` is a trait, and trait methods do not accept +turbofish syntax directly. The type must be inferred from the surrounding +context rather than specified at the call site. + +The correct ways to annotate an `into()` call are: + +**Option 1:** Annotate the binding with its expected type: + +``` +let y: i32 = 42; +let x: u32 = y.into(); // compiler infers `Into` from the annotation on `x` +``` + +**Option 2:** Use a type-ascription-style cast with `as` for primitive types: + +``` +let y: i32 = 42; +let x = y as u32; +``` + +**Option 3:** Use the fully-qualified syntax to name the trait explicitly: + +``` +let y: i32 = 42; +let x = Into::::into(y); +``` + +See also [E0035] for the error produced when turbofish is mistakenly used on a +trait method. + +[E0035]: https://doc.rust-lang.org/error_codes/E0035.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0308.md b/compiler/rustc_error_codes/src/error_codes/E0308.md index decee6309955a..a6d7ea104abcc 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0308.md +++ b/compiler/rustc_error_codes/src/error_codes/E0308.md @@ -24,3 +24,73 @@ This error occurs when an expression was used in a place where the compiler expected an expression of a different type. It can occur in several cases, the most common being when calling a function and passing an argument which has a different type than the matching type in the function declaration. + +## Common case: semicolon makes a function return `()` + +A frequent cause of E0308 for beginners is accidentally placing a semicolon +after the last expression in a function body. In Rust, a semicolon turns an +expression into a **statement** that evaluates to `()` (the unit type). When the +last statement in a function body is `()`, the function implicitly returns `()`, +even if the return type annotation says otherwise. + +```compile_fail,E0308 +fn add_one(x: i32) -> i32 { + x + 1; // error: expected `i32`, found `()` + // The semicolon discards the value and returns `()` instead +} +``` + +The fix is to remove the trailing semicolon so the expression's value is +returned directly: + +``` +fn add_one(x: i32) -> i32 { + x + 1 // ok: no semicolon — the value of `x + 1` is returned +} +``` + +Or use an explicit `return` statement (the semicolon after `return expr` is +optional): + +``` +fn add_one(x: i32) -> i32 { + return x + 1; // ok: explicit return +} +``` + +**Why does `()` appear in the error?** In Rust, `()` is the "unit type" — a +type with exactly one value (also written `()`). It is the implicit return type +of functions that do not return a meaningful value (like `fn foo() { ... }`). +When the compiler says `expected i32, found ()`, it means the function's body +evaluated to `()` (because of the semicolon) but the return type says `i32`. + +## Common case: function argument has wrong type + +When calling a function with a wrong argument type, the compiler reports the +expected type from the function's signature: + +```compile_fail,E0308 +fn greet(name: &str) { + println!("Hello, {}!", name); +} + +let name = String::from("Alice"); +greet(name); // error: expected `&str`, found `String` +``` + +A `String` is not the same as `&str`. You can borrow a `String` as `&str` with +`&`: + +``` +fn greet(name: &str) { + println!("Hello, {}!", name); +} + +let name = String::from("Alice"); +greet(&name); // ok: `&name` coerces to `&str` +``` + +If you are unsure which function is being called or what its full signature is, +check the documentation for the function or look at its definition — the +compiler's error message points to the location of the type mismatch, but the +function's declaration shows all parameter types at once. diff --git a/compiler/rustc_error_codes/src/error_codes/E0382.md b/compiler/rustc_error_codes/src/error_codes/E0382.md index cbc4980f8cab3..24aa1ced50ebc 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0382.md +++ b/compiler/rustc_error_codes/src/error_codes/E0382.md @@ -103,6 +103,79 @@ With this approach, x and y share ownership of the data via the `Rc` (reference count type). `RefCell` essentially performs runtime borrow checking: ensuring that at most one writer or multiple readers can access the data at any one time. +## E0382 in nested loops — "value moved in previous iteration" + +A subtle variant of this error occurs in **nested loops**, where a value is +moved inside an inner loop and then the outer loop tries to use it again. The +compiler may show messages like: + +- "value moved here, in previous iteration of loop" +- "this reinitialization might get skipped" + +These messages can be confusing. What they mean is: the **loop variable is +consumed (moved) inside the inner loop** and is no longer available when the +**outer loop** continues to its next iteration. + +```compile_fail,E0382 +fn process(s: String) { /* ... */ } + +fn main() { + 'outer: for item in vec!["a".to_string(), "b".to_string()] { + for _ in 0..3 { + process(item); // `item` is moved here on the first inner iteration + // error: use of moved value `item` — on the second inner iteration + // and on subsequent outer iterations + } + } +} +``` + +**Fix 1:** If you intended to move `item` and break out of the inner loop after +processing, use `continue 'outer` to skip to the next outer iteration +immediately after the move: + +``` +fn process(s: String) { /* ... */ } + +fn main() { + 'outer: for item in vec!["a".to_string(), "b".to_string()] { + for _ in 0..3 { + process(item); + continue 'outer; // move happened — jump to the next outer iteration + } + } +} +``` + +**Fix 2:** If you need to use `item` multiple times in the inner loop, clone or +borrow it instead of moving it: + +``` +fn process(s: &str) { /* ... */ } + +fn main() { + for item in &["a", "b"] { + for _ in 0..3 { + process(item); // borrow instead of move + } + } +} +``` + +**Fix 3:** If the type implements `Clone`, clone the value before each use: + +``` +fn process(s: String) { /* ... */ } + +fn main() { + for item in vec!["a".to_string(), "b".to_string()] { + for _ in 0..3 { + process(item.clone()); // clone so `item` is not consumed + } + } +} +``` + If you wish to learn more about ownership in Rust, start with the [Understanding Ownership][understanding-ownership] chapter in the Book. diff --git a/compiler/rustc_error_codes/src/error_codes/E0521.md b/compiler/rustc_error_codes/src/error_codes/E0521.md index fedf6365fb559..9323ff2947911 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0521.md +++ b/compiler/rustc_error_codes/src/error_codes/E0521.md @@ -1,4 +1,9 @@ -Borrowed data escapes outside of closure. +Borrowed data escapes outside of the closure body. + +"Escapes" means that the reference outlives the scope where it was borrowed — +the closure captures a reference to data, but tries to store it somewhere that +lives **longer** than the closure's body. This is a lifetime error, not a style +issue. Erroneous code example: @@ -10,19 +15,43 @@ let _add = |el: &str| { }; ``` -A type annotation of a closure parameter implies a new lifetime declaration. -Consider to drop it, the compiler is reliably able to infer them. +Why this is an error: `list` is declared outside the closure and has a longer +lifetime than the closure itself. When the explicit type annotation `el: &str` +is written on the closure parameter, the compiler infers a *new*, shorter +lifetime for `el` — one that is tied to the closure body. Trying to push `el` +into `list` (which has a longer lifetime) violates that lifetime constraint +because the reference could be used after the scope it was borrowed in. + +The fix is to drop the explicit type annotation and let the compiler infer the +lifetime. When no annotation is present, the compiler unifies `el`'s lifetime +with whatever `list` requires: ``` let mut list: Vec<&str> = Vec::new(); let _add = |el| { - list.push(el); + list.push(el); // ok: compiler infers a compatible lifetime for `el` }; ``` -See the [Closure type inference and annotation][closure-infere-annotation] and +Here is a clearer illustration of the lifetime mismatch: + +```compile_fail,E0521 +// The explicit annotation `el: &'closure str` creates a lifetime shorter +// than the `'outer` lifetime that `list: Vec<&'outer str>` requires. +fn example<'outer>(list: &mut Vec<&'outer str>) { + let _add = |el: &str| { + list.push(el); // `el` only lives as long as the closure body, + // but `list` needs references valid for `'outer` + }; +} +``` + +Consider dropping the type annotation so the compiler can infer the correct +lifetime automatically. + +See the [Closure type inference and annotation][closure-infer-annotation] and [Lifetime elision][lifetime-elision] sections of the Book for more details. -[closure-infere-annotation]: https://doc.rust-lang.org/book/ch13-01-closures.html#closure-type-inference-and-annotation +[closure-infer-annotation]: https://doc.rust-lang.org/book/ch13-01-closures.html#closure-type-inference-and-annotation [lifetime-elision]: https://doc.rust-lang.org/reference/lifetime-elision.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0603.md b/compiler/rustc_error_codes/src/error_codes/E0603.md index eb293118acc86..878af9cb5db0e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0603.md +++ b/compiler/rustc_error_codes/src/error_codes/E0603.md @@ -24,3 +24,32 @@ mod foo { println!("const value: {}", foo::PRIVATE); // ok! ``` + +**Note — possible false positive with `#[non_exhaustive]` enums:** + +If you are matching an enum from an external crate and see an error like +`unit variant 'Beta' is private`, but you know that enum variants cannot be +`private`, you may actually be hitting a `#[non_exhaustive]` restriction rather +than a true visibility error. The `#[non_exhaustive]` attribute prevents +downstream crates from matching an enum exhaustively without a wildcard arm, and +the compiler may incorrectly report it as E0603 in some situations. + +For `#[non_exhaustive]` enums, the correct fix is to add a wildcard arm to your +pattern match: + +```rust,ignore (pseudo-Rust) +// Given an external non_exhaustive enum: +// #[non_exhaustive] +// pub enum Status { Alpha, Beta, Gamma } + +match status { + Status::Alpha => { /* ... */ } + Status::Beta => { /* ... */ } + _ => { /* handle future variants */ } // required by #[non_exhaustive] +} +``` + +See [E0638] for the dedicated error covering `#[non_exhaustive]` pattern +matching requirements. + +[E0638]: https://doc.rust-lang.org/error_codes/E0638.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0638.md b/compiler/rustc_error_codes/src/error_codes/E0638.md index 14cd31502b670..c8d9b1638b507 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0638.md +++ b/compiler/rustc_error_codes/src/error_codes/E0638.md @@ -1,47 +1,93 @@ -This error indicates that the struct, enum or enum variant must be matched -non-exhaustively as it has been marked as `non_exhaustive`. +This error indicates that the struct, enum, or enum variant must be matched +non-exhaustively because it has been marked with the `#[non_exhaustive]` +attribute. -When applied within a crate, downstream users of the crate will need to use the -`_` pattern when matching enums and use the `..` pattern when matching structs. -Downstream crates cannot match against non-exhaustive enum variants. +The `#[non_exhaustive]` attribute signals that a type may gain new variants or +fields in future versions of the crate that defines it. Downstream crates +(crates other than the one that defines the type) are therefore required to use +wildcard patterns so their code does not break when new variants are added. -For example, in the below example, since the enum is marked as -`non_exhaustive`, it is required that downstream crates match non-exhaustively -on it. +**Rules for downstream crates:** + +- **Enums:** You must include a wildcard arm (`_ => ...`) in every `match` + expression on a `#[non_exhaustive]` enum. +- **Structs:** You must include `..` in every struct pattern. +- **Enum variants:** You cannot match against non-exhaustive enum variants + directly from outside the defining crate — you must match them as part of a + wildcard arm. + +When applied **within** the defining crate, the restriction does not apply and +the type may be matched exhaustively. + +**Example — matching a `#[non_exhaustive]` enum from another crate:** ```rust,ignore (pseudo-Rust) +// In `mycrate`: #[non_exhaustive] pub enum Error { Message(String), Other, } +``` -impl Display for Error { - fn fmt(&self, formatter: &mut fmt::Formatter) -> fmt::Result { - // This will not error, despite being marked as non_exhaustive, as this - // enum is defined within the current crate, it can be matched - // exhaustively. - let display = match self { - Message(s) => s, - Other => "other or unknown error", - }; - formatter.write_str(display) - } +Within `mycrate` itself, exhaustive matching is allowed: + +```rust,ignore (pseudo-Rust) +// Inside mycrate — this is fine +let display = match self { + Error::Message(s) => s.as_str(), + Error::Other => "other or unknown error", +}; +``` + +From a downstream crate, a wildcard arm is required: + +```rust,ignore (pseudo-Rust) +use mycrate::Error; + +// This will not error — the non_exhaustive enum is matched with a wildcard. +match error { + Error::Message(s) => println!("{}", s), + Error::Other => println!("other"), + _ => println!("unknown variant"), // required } ``` -An example of matching non-exhaustively on the above enum is provided below: +Omitting the wildcard in a downstream crate triggers E0638: ```rust,ignore (pseudo-Rust) use mycrate::Error; -// This will not error as the non_exhaustive Error enum has been matched with a -// wildcard. +// error[E0638]: `..` required with `#[non_exhaustive]` enum match error { - Message(s) => ..., - Other => ..., - _ => ..., + Error::Message(s) => println!("{}", s), + Error::Other => println!("other"), + // missing `_ => ...` } ``` -Similarly, for structs, match with `..` to avoid this error. +**Example — matching a `#[non_exhaustive]` struct:** + +```rust,ignore (pseudo-Rust) +// In `mycrate`: +#[non_exhaustive] +pub struct Config { + pub width: u32, + pub height: u32, +} +``` + +From a downstream crate, you must use `..` in struct patterns: + +```rust,ignore (pseudo-Rust) +use mycrate::Config; + +// ok: `..` accounts for any future fields +let Config { width, height, .. } = config; +``` + +**Note:** If you are seeing E0603 (`unit variant is private`) on an enum from +an external crate, but enum variants cannot be private, you may actually be +hitting this `#[non_exhaustive]` restriction. See [E0603] for details. + +[E0603]: https://doc.rust-lang.org/error_codes/E0603.html diff --git a/compiler/rustc_error_codes/src/error_codes/E0658.md b/compiler/rustc_error_codes/src/error_codes/E0658.md index 65c82e4fb6ef5..a4f99c6dfdd2e 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0658.md +++ b/compiler/rustc_error_codes/src/error_codes/E0658.md @@ -20,3 +20,42 @@ use std::intrinsics; // ok! ``` [rustup]: https://rust-lang.github.io/rustup/concepts/channels.html + +## Note — `let` in expression position + +Another source of E0658 (or a related parse error) is using `let` in a position +where an expression is expected. In Rust, `let` introduces a **statement**, not +an expression: + +```rust,ignore +fn main() { + // error: expected expression, found `let` statement + let x = (let y = 5); // `let` cannot be used as an expression here +} +``` + +The Rust book describes `let` as a statement that creates a variable binding. +It can only be used as an expression in the conditions of `if` and `while` (as +part of the `let`-chain feature), not in arbitrary expression positions. + +If you see the error message "expected expression, found `let` statement" or +"let expressions are not supported here", the fix is to use `let` as a normal +statement and restructure your code: + +``` +fn main() { + let y = 5; // ok: `let` as a statement + let x = y; + println!("{}", x); +} +``` + +For `if let` and `while let` chains (a nightly-only feature), the restriction +applies in positions outside of conditions: + +```rust,ignore +// ok on nightly with `#![feature(let_chains)]`: +if let Some(x) = opt1 && let Some(y) = opt2 { + // both bindings available here +} +``` diff --git a/compiler/rustc_parse/src/diagnostics.rs b/compiler/rustc_parse/src/diagnostics.rs index 238eebd73a0fa..07ec0757e2e9b 100644 --- a/compiler/rustc_parse/src/diagnostics.rs +++ b/compiler/rustc_parse/src/diagnostics.rs @@ -1332,6 +1332,7 @@ pub(crate) struct AttrWithoutWherePredicates { #[derive(Diagnostic)] #[diag("found a documentation comment that doesn't document anything", code = E0585)] #[help("doc comments must come before what they document, if a comment was intended use `//`")] +#[note("if the following item has a syntax error, fix that first — a syntax error can cause this warning to appear even when the doc comment placement is correct")] pub(crate) struct DocCommentDoesNotDocumentAnything { #[primary_span] pub span: Span,