From 72b3347d000473d06d90fc5112e74d160b65a0e8 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 23 Sep 2022 13:23:54 +0200 Subject: [PATCH 01/43] use correct location for type tests in promoted consts --- compiler/rustc_borrowck/src/type_check/mod.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index d03f036964857..3deffffe8a4f0 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -587,6 +587,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // modify their locations. let all_facts = &mut None; let mut constraints = Default::default(); + let mut type_tests = Default::default(); let mut closure_bounds = Default::default(); let mut liveness_constraints = LivenessValues::new(Rc::new(RegionValueElements::new(&promoted_body))); @@ -598,6 +599,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { &mut this.cx.borrowck_context.constraints.outlives_constraints, &mut constraints, ); + mem::swap(&mut this.cx.borrowck_context.constraints.type_tests, &mut type_tests); mem::swap( &mut this.cx.borrowck_context.constraints.closure_bounds_mapping, &mut closure_bounds, @@ -622,6 +624,13 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { swap_constraints(self); let locations = location.to_locations(); + + // Use location of promoted const in collected constraints + for type_test in type_tests.iter() { + let mut type_test = type_test.clone(); + type_test.locations = locations; + self.cx.borrowck_context.constraints.type_tests.push(type_test) + } for constraint in constraints.outlives().iter() { let mut constraint = constraint.clone(); constraint.locations = locations; From 29cc36f84cc68b71f6bc8f8fee786c605a8c5027 Mon Sep 17 00:00:00 2001 From: b-naber Date: Fri, 23 Sep 2022 14:03:13 +0200 Subject: [PATCH 02/43] add test --- src/test/ui/consts/issue-102117.rs | 30 +++++++++++++++++++++ src/test/ui/consts/issue-102117.stderr | 37 ++++++++++++++++++++++++++ 2 files changed, 67 insertions(+) create mode 100644 src/test/ui/consts/issue-102117.rs create mode 100644 src/test/ui/consts/issue-102117.stderr diff --git a/src/test/ui/consts/issue-102117.rs b/src/test/ui/consts/issue-102117.rs new file mode 100644 index 0000000000000..b77342c4135e1 --- /dev/null +++ b/src/test/ui/consts/issue-102117.rs @@ -0,0 +1,30 @@ +#![feature(inline_const, const_type_id)] + +use std::alloc::Layout; +use std::any::TypeId; +use std::mem::transmute; +use std::ptr::drop_in_place; + +pub struct VTable { + layout: Layout, + type_id: TypeId, + drop_in_place: unsafe fn(*mut ()), +} + +impl VTable { + pub fn new() -> &'static Self { + const { + //~^ ERROR the parameter type `T` may not live long enough + //~| ERROR the parameter type `T` may not live long enough + &VTable { + layout: Layout::new::(), + type_id: TypeId::of::(), + drop_in_place: unsafe { + transmute::(drop_in_place::) + }, + } + } + } +} + +fn main() {} diff --git a/src/test/ui/consts/issue-102117.stderr b/src/test/ui/consts/issue-102117.stderr new file mode 100644 index 0000000000000..eb4b329bd8134 --- /dev/null +++ b/src/test/ui/consts/issue-102117.stderr @@ -0,0 +1,37 @@ +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/issue-102117.rs:16:9 + | +LL | / const { +LL | | +LL | | +LL | | &VTable { +... | +LL | | } +LL | | } + | |_________^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | pub fn new() -> &'static Self { + | +++++++++ + +error[E0310]: the parameter type `T` may not live long enough + --> $DIR/issue-102117.rs:16:9 + | +LL | / const { +LL | | +LL | | +LL | | &VTable { +... | +LL | | } +LL | | } + | |_________^ ...so that the type `T` will meet its required lifetime bounds + | +help: consider adding an explicit lifetime bound... + | +LL | pub fn new() -> &'static Self { + | +++++++++ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0310`. From 39484ac3b0b80c1c98c4d46a9f88336c02f24da6 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 24 Sep 2022 17:20:23 +0100 Subject: [PATCH 03/43] Move style guide to rust-lang/rust Per [RFC 3309](https://rust-lang.github.io/rfcs/3309-style-team.html). --- src/bootstrap/builder.rs | 1 + src/bootstrap/doc.rs | 1 + src/doc/index.md | 6 + src/doc/style-guide/book.toml | 8 + src/doc/style-guide/src/README.md | 190 ++++++ src/doc/style-guide/src/SUMMARY.md | 11 + src/doc/style-guide/src/advice.md | 34 + src/doc/style-guide/src/cargo.md | 78 +++ src/doc/style-guide/src/expressions.md | 850 +++++++++++++++++++++++++ src/doc/style-guide/src/items.md | 565 ++++++++++++++++ src/doc/style-guide/src/principles.md | 51 ++ src/doc/style-guide/src/statements.md | 150 +++++ src/doc/style-guide/src/types.md | 58 ++ 13 files changed, 2003 insertions(+) create mode 100644 src/doc/style-guide/book.toml create mode 100644 src/doc/style-guide/src/README.md create mode 100644 src/doc/style-guide/src/SUMMARY.md create mode 100644 src/doc/style-guide/src/advice.md create mode 100644 src/doc/style-guide/src/cargo.md create mode 100644 src/doc/style-guide/src/expressions.md create mode 100644 src/doc/style-guide/src/items.md create mode 100644 src/doc/style-guide/src/principles.md create mode 100644 src/doc/style-guide/src/statements.md create mode 100644 src/doc/style-guide/src/types.md diff --git a/src/bootstrap/builder.rs b/src/bootstrap/builder.rs index bc6283ef467d6..4d1a1e084d529 100644 --- a/src/bootstrap/builder.rs +++ b/src/bootstrap/builder.rs @@ -704,6 +704,7 @@ impl<'a> Builder<'a> { doc::Miri, doc::EmbeddedBook, doc::EditionGuide, + doc::StyleGuide, ), Kind::Dist => describe!( dist::Docs, diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 819af6587484d..7bdd226cb692e 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -82,6 +82,7 @@ book!( Reference, "src/doc/reference", "reference", submodule; RustByExample, "src/doc/rust-by-example", "rust-by-example", submodule; RustdocBook, "src/doc/rustdoc", "rustdoc"; + StyleGuide, "src/doc/style-guide", "style-guide"; ); fn open(builder: &Builder<'_>, path: impl AsRef) { diff --git a/src/doc/index.md b/src/doc/index.md index 744c7f709a6db..bf08960f338a3 100644 --- a/src/doc/index.md +++ b/src/doc/index.md @@ -113,6 +113,12 @@ resources useful. [The Reference](reference/index.html) is not a formal spec, but is more detailed and comprehensive than the book. +## The Style Guide + +[The Rust Style Guide](style-guide/index.html) describes the standard formatting of Rust +code. Most developers use rustfmt to format their code, and rustfmt's default +formatting matches this style guide. + ## The Rustonomicon [The Rustonomicon](nomicon/index.html) is your guidebook to the dark arts of unsafe diff --git a/src/doc/style-guide/book.toml b/src/doc/style-guide/book.toml new file mode 100644 index 0000000000000..056aec8cdd4f6 --- /dev/null +++ b/src/doc/style-guide/book.toml @@ -0,0 +1,8 @@ +[book] +title = "The Rust Style Guide" +author = "The Rust Style Team" +multilingual = false +src = "src" + +[output.html] +git-repository-url = "https://github.com/rust-lang/rust/tree/HEAD/src/doc/style-guide/" diff --git a/src/doc/style-guide/src/README.md b/src/doc/style-guide/src/README.md new file mode 100644 index 0000000000000..adb73a7eef6e0 --- /dev/null +++ b/src/doc/style-guide/src/README.md @@ -0,0 +1,190 @@ +# Rust Style Guide + +## Motivation - why use a formatting tool? + +Formatting code is a mostly mechanical task which takes both time and mental +effort. By using an automatic formatting tool, a programmer is relieved of +this task and can concentrate on more important things. + +Furthermore, by sticking to an established style guide (such as this one), +programmers don't need to formulate ad hoc style rules, nor do they need to +debate with other programmers what style rules should be used, saving time, +communication overhead, and mental energy. + +Humans comprehend information through pattern matching. By ensuring that all +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. + + +## Formatting conventions + +### Indentation and line width + +* Use spaces, not tabs. +* 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. + + +### Blank lines + +Separate items and statements by either zero or one blank lines (i.e., one or +two newlines). E.g, + +```rust +fn foo() { + let x = ...; + + let y = ...; + let z = ...; +} + +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. + + +### [Module-level items](items.md) +### [Statements](statements.md) +### [Expressions](expressions.md) +### [Types](types.md) + + +### Comments + +The following guidelines for comments are recommendations only, a mechanical +formatter might skip formatting of comments. + +Prefer line comments (`//`) to block comments (`/* ... */`). + +When using line comments there should be a single space after the opening sigil. + +When using single-line block comments there should be a single space after the +opening sigil and before the closing sigil. Multi-line block comments should +have a newline after the opening sigil and before the closing sigil. + +Prefer to put a comment on its own line. Where a comment follows code, there +should be a single space before it. Where a block comment is inline, there +should be surrounding whitespace as if it were an identifier or keyword. There +should be no trailing whitespace after a comment or at the end of any line in a +multi-line comment. Examples: + +```rust +// A comment on an item. +struct Foo { ... } + +fn foo() {} // A comment after an item. + +pub fn foo(/* a comment before an argument */ x: T) {...} +``` + +Comments should usually be complete sentences. Start with a capital letter, end +with a period (`.`). An inline block comment may be treated as a note without +punctuation. + +Source lines which are entirely a comment should be limited to 80 characters +in length (including comment sigils, but excluding indentation) or the maximum +width of the line (including comment sigils and indentation), whichever is +smaller: + +```rust +// This comment goes up to the ................................. 80 char margin. + +{ + // This comment is .............................................. 80 chars wide. +} + +{ + { + { + { + { + { + // This comment is limited by the ......................... 100 char margin. + } + } + } + } + } +} +``` + +#### Doc comments + +Prefer line comments (`///`) to block comments (`/** ... */`). + +Prefer outer doc comments (`///` or `/** ... */`), only use inner doc comments +(`//!` and `/*! ... */`) to write module-level or crate-level documentation. + +Doc comments should come before attributes. + +### Attributes + +Put each attribute on its own line, indented to the level of the item. +In the case of inner attributes (`#!`), indent it to the level of the inside of +the item. Prefer outer attributes, where possible. + +For attributes with argument lists, format like functions. + +```rust +#[repr(C)] +#[foo(foo, bar)] +struct CRepr { + #![repr(C)] + x: f32, + y: f32, +} +``` + +For attributes with an equal sign, there should be a single space before and +after the `=`, e.g., `#[foo = 42]`. + +There must only be a single `derive` attribute. Note for tool authors: if +combining multiple `derive` attributes into a single attribute, the ordering of +the derived names should be preserved. E.g., `#[derive(bar)] #[derive(foo)] +struct Baz;` should be formatted to `#[derive(bar, foo)] struct Baz;`. + +### *small* items + +In many places in this guide we specify that a formatter may format an item +differently if it is *small*, for example struct literals: + +```rust +// Normal formatting +Foo { + f1: an_expression, + f2: another_expression(), +} + +// *small* formatting +Foo { f1, f2 } +``` + +We leave it to individual tools to decide on exactly what *small* means. In +particular, tools are free to use different definitions in different +circumstances. + +Some suitable heuristics are the size of the item (in characters) or the +complexity of an item (for example, that all components must be simple names, +not more complex sub-expressions). For more discussion on suitable heuristics, +see [this issue](https://github.com/rust-lang-nursery/fmt-rfcs/issues/47). + +Tools should give the user an option to ignore such heuristics and always use +the normal formatting. + + +## [Non-formatting conventions](advice.md) + +## [Cargo.toml conventions](cargo.md) + +## [Principles used for deciding these guidelines](principles.md) diff --git a/src/doc/style-guide/src/SUMMARY.md b/src/doc/style-guide/src/SUMMARY.md new file mode 100644 index 0000000000000..004692fa6a22b --- /dev/null +++ b/src/doc/style-guide/src/SUMMARY.md @@ -0,0 +1,11 @@ +# Summary + +[Introduction](README.md) + +- [Module-level items](items.md) +- [Statements](statements.md) +- [Expressions](expressions.md) +- [Types](types.md) +- [Non-formatting conventions](advice.md) +- [`Cargo.toml` conventions](cargo.md) +- [Principles used for deciding these guidelines](principles.md) diff --git a/src/doc/style-guide/src/advice.md b/src/doc/style-guide/src/advice.md new file mode 100644 index 0000000000000..ab4b92b0a2478 --- /dev/null +++ b/src/doc/style-guide/src/advice.md @@ -0,0 +1,34 @@ +# Other style advice + +## Expressions + +Prefer to use Rust's expression oriented nature where possible; + +```rust +// use +let x = if y { 1 } else { 0 }; +// not +let x; +if y { + x = 1; +} else { + x = 0; +} +``` + +## Names + + * Types shall be `UpperCamelCase`, + * Enum variants shall be `UpperCamelCase`, + * Struct fields shall be `snake_case`, + * Function and method names shall be `snake_case`, + * 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. + +### Modules + +Avoid `#[path]` annotations where possible. diff --git a/src/doc/style-guide/src/cargo.md b/src/doc/style-guide/src/cargo.md new file mode 100644 index 0000000000000..f4993ba06a888 --- /dev/null +++ b/src/doc/style-guide/src/cargo.md @@ -0,0 +1,78 @@ +# Cargo.toml conventions + +## Formatting conventions + +Use the same line width and indentation as Rust code. + +Put a blank line between the last key-value pair in a section and the header of +the next section. Do not place a blank line between section headers and the +key-value pairs in that section, or between key-value pairs in a section. + +Sort key names alphabetically within each section, with the exception of the +`[package]` section. Put the `[package]` section at the top of the file; put +the `name` and `version` keys in that order at the top of that section, +followed by the remaining keys other than `description` in alphabetical order, +followed by the `description` at the end of that section. + +Don't use quotes around any standard key names; use bare keys. Only use quoted +keys for non-standard keys whose names require them, and avoid introducing such +key names when possible. See the [TOML +specification](https://github.com/toml-lang/toml/blob/master/versions/en/toml-v0.4.0.md#table) +for details. + +Put a single space both before and after the `=` between a key and value. Do +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 +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 ", + "Another Author ", +] +``` + +For table values, such as a crate dependency with a path, write the entire +table using curly braces and commas on the same line as the key if it fits. If +the entire table does not fit on the same line as the key, separate it out into +a separate section with key-value pairs: + +```toml +[dependencies] +crate1 = { path = "crate1", version = "1.2.3" } + +[dependencies.extremely_long_crate_name_goes_here] +path = "extremely_long_path_name_goes_right_here" +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 `. +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), +using valid [SPDX license names](https://spdx.org/licenses/). (As an exception, +by widespread convention, the license field may use `/` in place of ` OR `; for +example, `MIT/Apache-2.0`.) + +The homepage field, if present, must consist of a single URL, including the +scheme (e.g. `https://example.org/`, not just `example.org`.) + +Within the description field, wrap text at 80 columns. Don't start the +description field with the name of the crate (e.g. "cratename is a ..."); just +describe the crate itself. If providing a multi-sentence description, the first +sentence should go on a line by itself and summarize the crate, like the +subject of an email or commit message; subsequent sentences can then describe +the crate in more detail. diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md new file mode 100644 index 0000000000000..d4352ef1c301e --- /dev/null +++ b/src/doc/style-guide/src/expressions.md @@ -0,0 +1,850 @@ +## Expressions + +### Blocks + +A block expression should have a newline after the initial `{` and before the +terminal `}`. Any qualifier before the block (e.g., `unsafe`) should always be +on the same line as the opening brace, and separated with a single space. The +contents of the block should be block indented: + +```rust +fn block_as_stmt() { + a_call(); + + { + a_call_inside_a_block(); + + // a comment in a block + the_value + } +} + +fn block_as_expr() { + let foo = { + a_call_inside_a_block(); + + // a comment in a block + the_value + }; +} + +fn unsafe_block_as_stmt() { + a_call(); + + unsafe { + a_call_inside_a_block(); + + // a comment in a block + the_value + } +} +``` + +If a block has an attribute, it should be on its own line: + +```rust +fn block_as_stmt() { + #[an_attribute] + { + #![an_inner_attribute] + + // a comment in a block + the_value + } +} +``` + +Avoid writing comments on the same line as the braces. + +An empty block should be written as `{}`. + +A block may be written on a single line if: + +* it is either used in expression position (not statement position) or is an + unsafe block in statement position +* contains a single-line expression and no statements +* contains no comments + +A single line block should have spaces after the opening brace and before the +closing brace. + +Examples: + +```rust +fn main() { + // Single line + let _ = { a_call() }; + let _ = unsafe { a_call() }; + + // Not allowed on one line + // Statement position. + { + a_call() + } + + // Contains a statement + let _ = { + a_call(); + }; + unsafe { + a_call(); + } + + // Contains a comment + let _ = { + // A comment + }; + let _ = { + // A comment + a_call() + }; + + // Multiple lines + let _ = { + a_call(); + another_call() + }; + let _ = { + a_call( + an_argument, + another_arg, + ) + }; +} +``` + + +### Closures + +Don't put any extra spaces before the first `|` (unless the closure is prefixed +by `move`); put a space between the second `|` and the expression of the +closure. Between the `|`s, you should use function definition syntax, however, +elide types where possible. + +Use closures without the enclosing `{}`, if possible. Add the `{}` when you have +a return type, when there are statements, there are comments in the body, or the +body expression spans multiple lines and is a control-flow expression. If using +braces, follow the rules above for blocks. Examples: + +```rust +|arg1, arg2| expr + +move |arg1: i32, arg2: i32| -> i32 { + expr1; + expr2 +} + +|| Foo { + field1, + field2: 0, +} + +|| { + if true { + blah + } else { + boo + } +} + +|x| unsafe { + expr +} +``` + + +### Struct literals + +If a struct literal is *small* it may be formatted on a single line. If not, +each field should be on it's own, block-indented line. There should be a +trailing comma in the multi-line form only. There should be a space after the +colon only. + +There should be a space before the opening brace. In the single-line form there +should be spaces after the opening brace and before the closing brace. + +```rust +Foo { field1, field2: 0 } +let f = Foo { + field1, + field2: an_expr, +}; +``` + +Functional record update syntax is treated like a field, but it must never have +a trailing comma. There should be no space after `..`. + +let f = Foo { + field1, + ..an_expr +}; + + +### Tuple literals + +Use a single-line form where possible. There should not be spaces around the +parentheses. Where a single-line form is not possible, each element of the tuple +should be on its own block-indented line and there should be a trailing comma. + +```rust +(a, b, c) + +let x = ( + a_long_expr, + another_very_long_expr, +); +``` + + +### Tuple struct literals + +There should be no space between the identifier and the opening parenthesis. +Otherwise, follow the rules for tuple literals, e.g., `Foo(a, b)`. + + +### Enum literals + +Follow the formatting rules for the various struct literals. Prefer using the +name of the enum as a qualifying name, unless the enum is in the prelude. E.g., + +```rust +Foo::Bar(a, b) +Foo::Baz { + field1, + field2: 1001, +} +Ok(an_expr) +``` + + +### Array literals + +For simple array literals, avoid line breaking, no spaces around square +brackets, contents of the array should be separated by commas and spaces. If +using the repeating initialiser, there should be a space after the semicolon +only. Apply the same rules if using the `vec!` or similar macros (always use +square brackets here). Examples: + +```rust +fn main() { + [1, 2, 3]; + vec![a, b, c, d]; + let a = [42; 10]; +} +``` + +If a line must be broken, prefer breaking only after the `;`, if possible. +Otherwise, follow the rules below for function calls. In any case, the contents +of the initialiser should be block indented and there should be line breaks +after the opening bracket and before the closing bracket: + +```rust +fn main() { + [ + a_long_expression(); + 1234567890 + ] + let x = [ + an_expression, + another_expression, + a_third_expression, + ]; +} +``` + + +### Array accesses, indexing, and slicing. + +No spaces around the square brackets, avoid breaking lines if possible, never +break a line between the target expression and the opening bracket. If the +indexing expression covers multiple lines, then it should be block indented and +there should be newlines after the opening brackets and before the closing +bracket. However, this should be avoided where possible. + +Examples: + +```rust +fn main() { + foo[42]; + &foo[..10]; + bar[0..100]; + foo[4 + 5 / bar]; + a_long_target[ + a_long_indexing_expression + ]; +} +``` + +### Unary operations + +Do not include a space between a unary op and its operand (i.e., `!x`, not +`! x`). However, there must be a space after `&mut`. Avoid line-breaking +between a unary operator and its operand. + +### Binary operations + +Do include spaces around binary ops (i.e., `x + 1`, not `x+1`) (including `=` +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. + +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., + +```rust +foo_bar + + bar + + baz + + qux + + whatever +``` + +Prefer line-breaking at an assignment operator (either `=` or `+=`, etc.) rather +than at other binary operators. + +### Control flow + +Do not include extraneous parentheses for `if` and `while` expressions. + +```rust +if true { +} +``` + +is better than + +```rust +if (true) { +} +``` + +Do include extraneous parentheses if it makes an arithmetic or logic expression +easier to understand (`(x * 15) + (y * 20)` is fine) + +### Function calls + +Do not put a space between the function name, and the opening parenthesis. + +Do not put a space between an argument, and the comma which follows. + +Do put a space between an argument, and the comma which precedes it. + +Prefer not to break a line in the callee expression. + +#### Single-line calls + +Do not put a space between the function name and open paren, between the open +paren and the first argument, or between the last argument and the close paren. + +Do not put a comma after the last argument. + +```rust +foo(x, y, z) +``` + +#### Multi-line calls + +If the function call is not *small*, it would otherwise over-run the max width, +or any argument or the callee is multi-line, then the call should be formatted +across multiple lines. In this case, each argument should be on it's own block- +indented line, there should be a newline after the opening parenthesis and +before the closing parenthesis, and there should be a trailing comma. E.g., + +```rust +a_function_call( + arg1, + a_nested_call(a, b), +) +``` + + +### Method calls + +Follow the function rules for calling. + +Do not put any spaces around the `.`. + +```rust +x.foo().bar().baz(x, y, z); +``` + + +### Macro uses + +Macros which can be parsed like other constructs should be formatted like those +constructs. For example, a macro use `foo!(a, b, c)` can be parsed like a +function call (ignoring the `!`), therefore it should be formatted following the +rules for function calls. + +#### Special case macros + +Macros which take a format string and where all other arguments are *small* may +be formatted with arguments before and after the format string on a single line +and the format string on its own line, rather than putting each argument on its +own line. For example, + +```rust +println!( + "Hello {} and {}", + name1, name2, +); + +assert_eq!( + x, y, + "x and y were not equal, see {}", + reason, +); +``` + + +### Casts (`as`) + +Put spaces before and after `as`: + +```rust +let cstr = "Hi\0" as *const str as *const [u8] as *const std::os::raw::c_char; +``` + + +### Chains of fields and method calls + +A chain is a sequence of field accesses and/or method calls. A chain may also +include the try operator ('?'). E.g., `a.b.c().d` or `foo?.bar().baz?`. + +Prefer formatting on one line if possible, and the chain is *small*. If +formatting on multiple lines, each field access or method call in the chain +should be on its own line with the line-break before the `.` and after any `?`. +Each line should be block-indented. E.g., + +```rust +let foo = bar + .baz? + .qux(); +``` + +If the length of the last line of the first element plus its indentation is +less than or equal to the indentation of the second line (and there is space), +then combine the first and second lines, e.g., + +```rust +x.baz? + .qux() + +let foo = x + .baz? + .qux(); + +foo( + expr1, + expr2, +).baz? + .qux(); +``` + +#### Multi-line elements + +If any element in a chain is formatted across multiple lines, then that element +and any later elements must be on their own line. Earlier elements may be kept +on a single line. E.g., + +```rust +a.b.c()?.d + .foo( + an_expr, + another_expr, + ) + .bar + .baz +``` + +Note there is block indent due to the chain and the function call in the above +example. + +Prefer formatting the whole chain in multi-line style and each element on one +line, rather than putting some elements on multiple lines and some on a single +line, e.g., + +```rust +// Better +self.pre_comment + .as_ref() + .map_or(false, |comment| comment.starts_with("//")) + +// Worse +self.pre_comment.as_ref().map_or( + false, + |comment| comment.starts_with("//"), +) +``` + +### Control flow expressions + +This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for` +expressions. + +The keyword, any initial clauses, and the opening brace of the block should be +on a single line. The usual rules for [block formatting](#Blocks) should be +applied to the block. + +If there is an `else` component, then the closing brace, `else`, any following +clause, and the opening brace should all be on the same line. There should be a +single space before and after the `else` keyword. For example: + +```rust +if ... { + ... +} else { + ... +} + +if let ... { + ... +} else if ... { + ... +} else { + ... +} +``` + +If the control line needs to be broken, then prefer to break before the `=` in +`* let` expressions and before `in` in a `for` expression; the following line +should be block indented. If the control line is broken for any reason, then the +opening brace should be on its own line and not indented. Examples: + +```rust +while let Some(foo) + = a_long_expression +{ + ... +} + +for foo + in a_long_expression +{ + ... +} + +if a_long_expression + && another_long_expression + || a_third_long_expression +{ + ... +} +``` + +Where the initial clause is multi-lined and ends with one or more closing +parentheses, square brackets, or braces, and there is nothing else on that line, +and that line is not indented beyond the indent on the first line of the control +flow expression, then the opening brace of the block should be put on the same +line with a preceding space. For example: + +```rust +if !self.config.file_lines().intersects( + &self.codemap.lookup_line_range( + stmt.span, + ), +) { // Opening brace on same line as initial clause. + ... +} +``` + + +#### Single line `if else` + +Formatters may place an `if else` or `if let else` on a single line if it occurs +in expression context (i.e., is not a standalone statement), it contains a +single `else` clause, and is *small*. For example: + +```rust +let y = if x { 0 } else { 1 }; + +// Examples that must be multi-line. +let y = if something_very_long { + not_small +} else { + also_not_small +}; + +if x { + 0 +} else { + 1 +} +``` + + +### Match + +Prefer not to line-break inside the discriminant expression. There must always +be a line break after the opening brace and before the closing brace. The match +arms must be block indented once: + +```rust +match foo { + // arms +} + +let x = match foo.bar.baz() { + // arms +}; +``` + +Use a trailing comma for a match arm if and only if not using a block. + +Never start a match arm pattern with `|`, e.g., + +```rust +match foo { + // Don't do this. + | foo => bar, + // Or this. + | a_very_long_pattern + | another_pattern + | yet_another_pattern + | a_forth_pattern => { + ... + } +} +``` + +Prefer + + +```rust +match foo { + foo => bar, + a_very_long_pattern + | another_pattern + | yet_another_pattern + | a_forth_pattern => { + ... + } +} +``` + +Avoid splitting the left-hand side (before the `=>`) of a match arm where +possible. If the right-hand side of the match arm is kept on the same line, +never use a block (unless the block is empty). + +If the right-hand side consists of multiple statements or has line comments or +the start of the line cannot be fit on the same line as the left-hand side, use +a block. + +The body of a block arm should be block indented once. + +Examples: + +```rust +match foo { + foo => bar, + a_very_long_patten | another_pattern if an_expression() => { + no_room_for_this_expression() + } + foo => { + // A comment. + an_expression() + } + foo => { + let a = statement(); + an_expression() + } + bar => {} + // Trailing comma on last item. + foo => bar, +} +``` + +If the body is a single expression with no line comments and not a control flow +expression, then it may be started on the same line as the right-hand side. If +not, then it must be in a block. Example, + +```rust +match foo { + // A combinable expression. + foo => a_function_call(another_call( + argument1, + argument2, + )), + // A non-combinable expression + bar => { + a_function_call( + another_call( + argument1, + argument2, + ), + another_argument, + ) + } +} +``` + +#### Line-breaking + +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 + a_very_long_pattern | another_pattern => ALongStructName { + ... + }, + // Prefer this + a_very_long_pattern | another_pattern => { + ALongStructName { + ... + } + } + // To splitting the pattern. +``` + +Never break after `=>` without using the block form of the body. + +If the left-hand side must be split and there is an `if` clause, break before +the `if` and block indent. In this case, always use a block body and start the +body on a new line: + +```rust + a_very_long_pattern | another_pattern + if expr => + { + ... + } +``` + +If required to break the pattern, put each clause of the pattern on its own +line with no additional indent, breaking before the `|`. If there is an `if` +clause, then you must use the above form: + +```rust + a_very_long_pattern + | another_pattern + | yet_another_pattern + | a_forth_pattern => { + ... + } + a_very_long_pattern + | another_pattern + | yet_another_pattern + | a_forth_pattern + if expr => + { + ... + } +``` + +If the pattern is multi-line, and the last line is less wide than the indent, do +not put the `if` clause on a newline. E.g., + +```rust + Token::Dimension { + value, + ref unit, + .. + } if num_context.is_ok(context.parsing_mode, value) => { + ... + } +``` + +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 `|`: + +```rust + foo | bar | baz + | qux => { + ... + } +``` + +We define a pattern clause to be *small* if it matches the following grammar: + +``` +[small, ntp]: + - single token + - `&[single-line, ntp]` + +[small]: + - `[small, ntp]` + - unary tuple constructor `([small, ntp])` + - `&[small]` +``` + +E.g., `&&Some(foo)` matches, `Foo(4, Bar)` does not. + + +### Combinable expressions + +Where a function call has a single argument, and that argument is formatted +across multiple-lines, the outer call may be formatted as if it were a single- +line call. The same combining behaviour may be applied to any similar +expressions which have multi-line, block-indented lists of sub-expressions +delimited by parentheses (e.g., macros or tuple struct literals). E.g., + +```rust +foo(bar( + an_expr, + another_expr, +)) + +let x = foo(Bar { + field: whatever, +}); + +foo(|param| { + action(); + foo(param) +}) +``` + +Such behaviour should extend recursively, however, tools may choose to limit the +depth of nesting. + +Only where the multi-line sub-expression is a closure with an explicit block, +this combining behaviour may be used where there are other arguments, as long as +all the arguments and the first line of the closure fit on the first line, the +closure is the last argument, and there is only one closure argument: + +```rust +foo(first_arg, x, |param| { + action(); + foo(param) +}) +``` + + +### Ranges + +Do not put spaces in ranges, e.g., `0..10`, `x..=y`, `..x.len()`, `foo..`. + +When writing a range with both upper and lower bounds, if the line must be +broken, break before the range operator and block indent the second line: + +```rust +a_long_expression + ..another_long_expression +``` + +For the sake of indicating precedence, we recommend that if either bound is a +compound expression, then use parentheses around it, e.g., `..(x + 1)`, +`(x.f)..(x.f.len())`, or `0..(x - 10)`. + + +### Hexadecimal literals + +Hexadecimal literals may use upper- or lower-case letters, but they must not be +mixed within the same literal. Projects should use the same case for all +literals, but we do not make a recommendation for either lower- or upper-case. +Tools should have an option to convert mixed case literals to upper-case, and +may have an option to convert all literals to either lower- or upper-case. + + +## Patterns + +Patterns should be formatted like their corresponding expressions. See the +section on `match` for additional formatting for patterns in match arms. diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md new file mode 100644 index 0000000000000..324071eb39a5a --- /dev/null +++ b/src/doc/style-guide/src/items.md @@ -0,0 +1,565 @@ +## Items + +`extern crate` statements must be first in a file. They must be ordered +alphabetically. + +`use` statements, and module *declarations* (`mod foo;`, not `mod { ... }`) +must come before other items. We recommend that imports come before module +declarations; if imports and modules are separated, then they should be ordered +alphabetically. When sorting, `self` and `super` must come before any other +names. Module declarations should not be moved if they are annotated with +`#[macro_use]`, since that may be semantics changing. + +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. + +The proper ordering and spacing is: + +```rust +[pub] [unsafe] [extern ["ABI"]] fn foo(arg1: i32, arg2: i32) -> i32 { + ... +} +``` + +Avoid comments within the signature itself. + +If the function signature does not fit on one line, then break after the opening +parenthesis and before the closing parenthesis and put each argument on its own +block-indented line. For example, + +```rust +fn foo( + arg1: i32, + arg2: i32, +) -> i32 { + ... +} +``` + +Note the trailing comma on the last argument. + + +### Tuples and tuple structs + +Write the type list as you would a parameter list to a function. + +Build a tuple or tuple struct as you would call a function. + +#### Single-line + +```rust +struct Bar(Type1, Type2); + +let x = Bar(11, 22); +let y = (11, 22, 33); +``` + +### Enums + +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. + +```rust +enum FooBar { + First(u32), + Second, + Error { + err: Box, + line: u32, + }, +} +``` + +If a struct variant is [*small*](#small-items), it may be formatted on +one line. In this case, do not use a trailing comma for the field list, but do +put spaces around each brace: + +```rust +enum FooBar { + Error { err: Box, line: u32 }, +} +``` + +In an enum with multiple struct variants, if any struct variant is written on +multiple lines, then the multi-line formatting should be used for all struct +variants. However, such a situation might be an indication that you should +factor out the fields of the variant into their own struct. + + +### Structs and Unions + +Struct names follow on the same line as the `struct` keyword, with the opening +brace on the same line when it fits within the right margin. All struct fields +are indented once and end with a trailing comma. The closing brace is not +indented and appears on its own line. + +```rust +struct Foo { + a: A, + b: B, +} +``` + +If and only if the type of a field does not fit within the right margin, it is +pulled down to its own line and indented again. + +```rust +struct Foo { + a: A, + long_name: + LongType, +} +``` + +Prefer using a unit struct (e.g., `struct Foo;`) to an empty struct (e.g., +`struct Foo();` or `struct Foo {}`, these only exist to simplify code +generation), but if you must use an empty struct, keep it on one line with no +space between the braces: `struct Foo;` or `struct Foo {}`. + +The same guidelines are used for untagged union declarations. + +```rust +union Foo { + a: A, + b: B, + long_name: + LongType, +} +``` + + +### Tuple structs + +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: + +```rust +pub struct Foo(String, u8); +``` + +Prefer unit structs to empty tuple structs (these only exist to simplify code +generation), e.g., `struct Foo;` rather than `struct Foo();`. + +For more than a few fields, prefer a proper struct with named fields. Given +this, a tuple struct should always fit on one line. If it does not, block format +the fields with a field on each line and a trailing comma: + +```rust +pub struct Foo( + String, + u8, +); +``` + + +### Traits + +Trait items should be block-indented. If there are no items, the trait may be +formatted on a single line. Otherwise there should be line-breaks after the +opening brace and before the closing brace: + +```rust +trait Foo {} + +pub trait Bar { + ... +} +``` + +If the trait has bounds, there should be a space after the colon but not before +and before and after each `+`, e.g., + +```rust +trait Foo: Debug + Bar {} +``` + +Prefer not to line-break in the bounds if possible (consider using a `where` +clause). Prefer to break between bounds than to break any individual bound. If +you must break the bounds, put each bound (including the first) on its own +block-indented line, break before the `+` and put the opening brace on its own +line: + +```rust +pub trait IndexRanges: + Index, Output=Self> + + Index, Output=Self> + + Index, Output=Self> + + Index +{ + ... +} +``` + + +### Impls + +Impl items should be block indented. If there are no items, the impl may be +formatted on a single line. Otherwise there should be line-breaks after the +opening brace and before the closing brace: + +```rust +impl Foo {} + +impl Bar for Foo { + ... +} +``` + +Avoid line-breaking in the signature if possible. If a line break is required in +a non-inherent impl, break immediately before `for`, block indent the concrete type +and put the opening brace on its own line: + +```rust +impl Bar + for Foo +{ + ... +} +``` + + +### Extern crate + +`extern crate foo;` + +Use spaces around keywords, no spaces around the semi-colon. + + +### Modules + +```rust +mod foo { +} +``` + +```rust +mod foo; +``` + +Use spaces around keywords and before the opening brace, no spaces around the +semi-colon. + +### macro\_rules! + +Use `{}` for the full definition of the macro. + +```rust +macro_rules! foo { +} +``` + + +### Generics + +Prefer to put a generics clause on one line. Break other parts of an item +declaration rather than line-breaking a generics clause. If a generics clause is +large enough to require line-breaking, you should prefer to use a `where` clause +instead. + +Do not put spaces before or after `<` nor before `>`. Only put a space after `>` +if it is followed by a word or opening brace, not an opening parenthesis. There +should be a space after each comma and no trailing comma. + +```rust +fn foo(x: Vec, y: Vec) ... + +impl SomeType { ... +``` + +If the generics clause must be formatted across multiple lines, each parameter +should have its own block-indented line, there should be newlines after the +opening bracket and before the closing bracket, and the should be a trailing +comma. + +```rust +fn foo< + T: Display, + U: Debug, +>(x: Vec, y: Vec) ... +``` + +If an associated type is bound in a generic type, then there should be spaces on +either side of the `=`: + +```rust +> +``` + +Prefer to use single-letter names for generic parameters. + + +### `where` clauses + +These rules apply for `where` clauses on any item. + +A `where` clause may immediately follow a closing bracket of any kind. +Otherwise, it must start a new line, with no indent. Each component of a `where` +clause must be on its own line and be block indented. There should be a trailing +comma, unless the clause is terminated with a semicolon. If the `where` clause +is followed by a block (or assignment), the block should be started on a new +line. Examples: + +```rust +fn function(args) +where + T: Bound, + U: AnotherBound, +{ + body +} + +fn foo( + args +) -> ReturnType +where + T: Bound, +{ + body +} + +fn foo( + args, +) where + T: Bound, + U: AnotherBound, +{ + body +} + +fn foo( + args +) -> ReturnType +where + T: Bound, + U: AnotherBound; // Note, no trailing comma. + +// Note that where clauses on `type` aliases are not enforced and should not +// be used. +type Foo +where + T: Bound += Bar; +``` + +If a `where` clause is very short, we recommend using an inline bound on the +type parameter. + + +If a component of a `where` clause is long, it may be broken before `+` and +further block indented. Each bound should go on its own line. E.g., + +```rust +impl IndexRanges for T +where + T: Index, Output = Self::Output> + + Index, Output = Self::Output> + + Index, Output = Self::Output> + + Index, Output = Self::Output> + + Index, Output = Self::Output> + Index +``` + +#### Option - `where_single_line` + +`where_single_line` is `false` by default. If `true`, then a where clause with +exactly one component may be formatted on a single line if the rest of the +item's signature is also kept on one line. In this case, there is no need for a +trailing comma and if followed by a block, no need for a newline before the +block. E.g., + +```rust +// May be single-lined. +fn foo(args) -> ReturnType +where T: Bound { + body +} + +// Must be multi-lined. +fn foo( + args +) -> ReturnType +where + T: Bound, +{ + body +} +``` + + +### Type aliases + +Type aliases should generally be kept on one line. If necessary to break the +line, do so after the `=`; the right-hand-side should be block indented: + +```rust +pub type Foo = Bar; + +// If multi-line is required +type VeryLongType = + AnEvenLongerType>; +``` + +Where possible avoid `where` clauses and keep type constraints inline. Where +that is not possible split the line before and after the `where` clause (and +split the `where` clause as normal), e.g., + +```rust +type VeryLongType +where + T: U::AnAssociatedType, + U: SomeBound, += AnEvenLongerType>; +``` + + +### Associated types + +Associated types should follow the guidelines above for type aliases. Where an +associated type has a bound, there should be a space after the colon but not +before: + +```rust +pub type Foo: Bar; +``` + + +### extern items + +When writing extern items (such as `extern "C" fn`), always be explicit about +the ABI. For example, write `extern "C" fn foo ...`, not `extern fn foo ...`, or +`extern "C" { ... }`. + + +### Imports (`use` statements) + +If an import can be formatted on one line, do so. There should be no spaces +around braces. + +```rust +use a::b::c; +use a::b::d::*; +use a::b::{foo, bar, baz}; +``` + + +#### Large list imports + +Prefer to use multiple imports rather than a multi-line import. However, tools +should not split imports by default (they may offer this as an option). + +If an import does require multiple lines (either because a list of single names +does not fit within the max width, or because of the rules for nested imports +below), then break after the opening brace and before the closing brace, use a +trailing comma, and block indent the names. + + +```rust +// Prefer +foo::{long, list, of, imports}; +foo::{more, imports}; + +// If necessary +foo::{ + long, list, of, imports, more, + imports, // Note trailing comma +}; +``` + + +#### Ordering of imports + +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. + + +E.g., input: + +```rust +use d; +use c; + +use b; +use a; +``` + +output: + +```rust +use c; +use d; + +use a; +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 +`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}};`. + + +#### Normalisation + +Tools must make the following normalisations: + +* `use a::self;` -> `use a;` +* `use a::{};` -> (nothing) +* `use a::{b};` -> `use a::b;` + +And must apply these recursively. + +Tools must not otherwise merge or un-merge import lists or adjust glob imports +(without an explicit option). + + +#### Nested imports + +If there are any nested imports in a list import, then use the multi-line form, +even if the import fits on one line. Each nested import must be on its own line, +but non-nested imports must be grouped on as few lines as possible. + +For example, + +```rust +use a::b::{ + x, y, z, + u::{...}, + w::{...}, +}; +``` + + +#### Merging/un-merging imports + +An example: + +```rust +// Un-merged +use a::b; +use a::c::d; + +// Merged +use a::{b, c::d}; +``` + +Tools must not merge or un-merge imports by default. They may offer merging or +un-merging as an option. diff --git a/src/doc/style-guide/src/principles.md b/src/doc/style-guide/src/principles.md new file mode 100644 index 0000000000000..b02b3c0471f28 --- /dev/null +++ b/src/doc/style-guide/src/principles.md @@ -0,0 +1,51 @@ +# Guiding principles and rationale + +When deciding on style guidelines, the style team tried to be guided by the +following principles (in rough priority order): + +* readability + - scan-ability + - avoiding misleading formatting + - accessibility - readable and editable by users using the the widest + variety of hardware, including non-visual accessibility interfaces + - readability of code when quoted in rustc error messages + +* aesthetics + - sense of 'beauty' + - consistent with other languages/tools + +* specifics + - compatibility with version control practices - preserving diffs, + merge-friendliness, etc. + - preventing right-ward drift + - minimising vertical space + +* application + - ease of manual application + - 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 new file mode 100644 index 0000000000000..9c3eba12d2ecb --- /dev/null +++ b/src/doc/style-guide/src/statements.md @@ -0,0 +1,150 @@ +### Let statements + +There should be spaces after the `:` and on both sides of the `=` (if they are +present). No space before the semi-colon. + +```rust +// A comment. +let pattern: Type = expr; + +let pattern; +let pattern: Type; +let pattern = expr; +``` + +If possible the declaration should be formatted on a single line. If this is not +possible, then try splitting after the `=`, if the declaration can fit on two +lines. The expression should be block indented. + +```rust +let pattern: Type = + expr; +``` + +If the first line does not fit on a single line, then split after the colon, +using block indentation. If the type covers multiple lines, even after line- +breaking after the `:`, then the first line may be placed on the same line as +the `:`, subject to the [combining rules](https://github.com/rust-lang-nursery/fmt-rfcs/issues/61) (WIP). + + +```rust +let pattern: + Type = + expr; +``` + +e.g, + +```rust +let Foo { + f: abcd, + g: qwer, +}: Foo = + Foo { f, g }; + +let (abcd, + defg): + Baz = +{ ... } +``` + +If the expression covers multiple lines, if the first line of the expression +fits in the remaining space, it stays on the same line as the `=`, the rest of the +expression is not indented. If the first line does not fit, then it should start +on the next lines, and should be block indented. If the expression is a block +and the type or pattern cover multiple lines, then the opening brace should be +on a new line and not indented (this provides separation for the interior of the +block from the type), otherwise the opening brace follows the `=`. + +Examples: + +```rust +let foo = Foo { + f: abcd, + g: qwer, +}; + +let foo = + ALongName { + f: abcd, + g: qwer, + }; + +let foo: Type = { + an_expression(); + ... +}; + +let foo: + ALongType = +{ + an_expression(); + ... +}; + +let Foo { + f: abcd, + g: qwer, +}: Foo = Foo { + f: blimblimblim, + g: blamblamblam, +}; + +let Foo { + f: abcd, + g: qwer, +}: Foo = foo( + blimblimblim, + blamblamblam, +); +``` + + +### 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 +between the name, `!`, the delimiters, or the `;`. + +```rust +// A comment. +a_macro!(...); +``` + + +### Expressions in statement position + +There should be no space between the expression and the semi-colon. + +``` +; +``` + +All expressions in statement position should be terminated with a semi-colon, +unless they end with a block or are used as the value for a block. + +E.g., + +```rust +{ + an_expression(); + expr_as_value() +} + +return foo(); + +loop { + break; +} +``` + +Use a semi-colon where an expression has void type, even if it could be +propagated. E.g., + +```rust +fn foo() { ... } + +fn bar() { + foo(); +} +``` diff --git a/src/doc/style-guide/src/types.md b/src/doc/style-guide/src/types.md new file mode 100644 index 0000000000000..25861ddabb8d0 --- /dev/null +++ b/src/doc/style-guide/src/types.md @@ -0,0 +1,58 @@ +## Types and Bounds + +### Single line formatting + +* `[T]` no spaces +* `[T; expr]`, e.g., `[u32; 42]`, `[Vec; 10 * 2 + foo()]` (space after colon, no spaces around square brackets) +* `*const T`, `*mut T` (no space after `*`, space before type) +* `&'a T`, `&T`, `&'a mut T`, `&mut T` (no space after `&`, single spaces separating other words) +* `unsafe extern "C" fn<'a, 'b, 'c>(T, U, V) -> W` or `fn()` (single spaces around keyowrds and sigils, and after commas, no trailing commas, no spaces around brackets) +* `!` should be treated like any other type name, `Name` +* `(A, B, C, D)` (spaces after commas, no spaces around parens, no trailing comma unless it is a one-tuple) +* ` as SomeTrait>::Foo::Bar` or `Foo::Bar` or `::Foo::Bar` (no spaces around `::` or angle brackets, single spaces around `as`) +* `Foo::Bar` (spaces after commas, no trailing comma, no spaces around angle brackets) +* `T + T + T` (single spaces between types, and `+`). +* `impl T + T + T` (single spaces between keyword, types, and `+`). + +Parentheses used in types should not be surrounded by whitespace, e.g., `(Foo)` + + +### Line breaks + +Avoid breaking lines in types where possible. Prefer breaking at outermost scope, e.g., prefer + +```rust +Foo< + Bar, + Baz, +> +``` + +to + +```rust +Foo> +``` + +`[T; expr]` may be broken after the `;` if necessary. + +Function types may be broken following the rules for function declarations. + +Generic types may be broken following the rules for generics. + +Types with `+` may be broken after any `+` using block indent and breaking before the `+`. When breaking such a type, all `+`s should be line broken, e.g., + +```rust +impl Clone + + Copy + + Debug + +Box< + Clone + + Copy + + Debug +> +``` From 9a9e8273e4ba8d308f8ce261a4694dc5b42fac9d Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 24 Sep 2022 17:25:38 +0100 Subject: [PATCH 04/43] triagebot.toml: Add autolabel for T-style --- triagebot.toml | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/triagebot.toml b/triagebot.toml index d358e59c24525..181fb1de93055 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -189,6 +189,11 @@ trigger_files = [ "src/tools/bump-stage0", ] +[autolabel."T-style"] +trigger_files = [ + "src/doc/style-guide", +] + [autolabel."A-translation"] trigger_files = [ "compiler/rustc_error_messages", From 283c0e43caf6d61f4fdaf1320904cd34d7abff9e Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 24 Sep 2022 17:40:08 +0100 Subject: [PATCH 05/43] style-guide: Remove trailing space --- src/doc/style-guide/src/expressions.md | 4 ++-- src/doc/style-guide/src/items.md | 4 ++-- src/doc/style-guide/src/statements.md | 4 ++-- 3 files changed, 6 insertions(+), 6 deletions(-) diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index d4352ef1c301e..dfa24549b5780 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -294,7 +294,7 @@ 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 +If line-breaking, put the operator on a new line and block indent. Put each sub-expression on its own line. E.g., ```rust @@ -595,7 +595,7 @@ let x = match foo.bar.baz() { }; ``` -Use a trailing comma for a match arm if and only if not using a block. +Use a trailing comma for a match arm if and only if not using a block. Never start a match arm pattern with `|`, e.g., diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index 324071eb39a5a..7439c68d92c7d 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -113,7 +113,7 @@ pulled down to its own line and indented again. ```rust struct Foo { a: A, - long_name: + long_name: LongType, } ``` @@ -129,7 +129,7 @@ The same guidelines are used for untagged union declarations. union Foo { a: A, b: B, - long_name: + long_name: LongType, } ``` diff --git a/src/doc/style-guide/src/statements.md b/src/doc/style-guide/src/statements.md index 9c3eba12d2ecb..29b48bb1ee0b7 100644 --- a/src/doc/style-guide/src/statements.md +++ b/src/doc/style-guide/src/statements.md @@ -79,14 +79,14 @@ let foo: ALongType = { an_expression(); - ... + ... }; let Foo { f: abcd, g: qwer, }: Foo = Foo { - f: blimblimblim, + f: blimblimblim, g: blamblamblam, }; From 9a72a668505f403f2ecdb63fdfd4df315b938c6b Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Sat, 24 Sep 2022 19:55:33 +0100 Subject: [PATCH 06/43] style-guide: Fix broken links --- src/doc/style-guide/src/expressions.md | 2 +- src/doc/style-guide/src/items.md | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/doc/style-guide/src/expressions.md b/src/doc/style-guide/src/expressions.md index dfa24549b5780..c7d0446dded19 100644 --- a/src/doc/style-guide/src/expressions.md +++ b/src/doc/style-guide/src/expressions.md @@ -489,7 +489,7 @@ This section covers `if`, `if let`, `loop`, `while`, `while let`, and `for` expressions. The keyword, any initial clauses, and the opening brace of the block should be -on a single line. The usual rules for [block formatting](#Blocks) should be +on a single line. The usual rules for [block formatting](#blocks) should be applied to the block. If there is an `else` component, then the closing brace, `else`, any following diff --git a/src/doc/style-guide/src/items.md b/src/doc/style-guide/src/items.md index 7439c68d92c7d..2835975355fca 100644 --- a/src/doc/style-guide/src/items.md +++ b/src/doc/style-guide/src/items.md @@ -77,7 +77,7 @@ enum FooBar { } ``` -If a struct variant is [*small*](#small-items), it may be formatted on +If a struct variant is [*small*](index.html#small-items), it may be formatted on one line. In this case, do not use a trailing comma for the field list, but do put spaces around each brace: From 69cafc069900905b2b48661dd013ade13186345e Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 2 Oct 2022 14:24:56 +0200 Subject: [PATCH 07/43] always panic for invalid integer logarithm --- library/core/src/num/int_macros.rs | 45 +++++------------------------ library/core/src/num/uint_macros.rs | 43 +++++---------------------- 2 files changed, 15 insertions(+), 73 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index d6aeee299e30d..4eb85a281e20d 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2279,9 +2279,8 @@ macro_rules! int_impl { /// /// # Panics /// - /// When the number is negative, zero, or if the base is not at least 2; it - /// panics in debug mode and the return value is 0 in release - /// mode. + /// This function will panic if `self` is less than or equal to zero, + /// or if `base` is less then 2. /// /// # Examples /// @@ -2297,24 +2296,15 @@ macro_rules! int_impl { #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] pub const fn ilog(self, base: Self) -> u32 { - match self.checked_ilog(base) { - Some(n) => n, - None => { - // In debug builds, trigger a panic on None. - // This should optimize completely out in release builds. - let _ = Self::MAX + 1; - - 0 - }, - } + assert!(base >= 2, "base of integer logarithm must be at least 2"); + self.checked_ilog(base).expect("argument of integer logarithm must be positive") } /// Returns the base 2 logarithm of the number, rounded down. /// /// # Panics /// - /// When the number is negative or zero it panics in debug mode and the return value - /// is 0 in release mode. + /// This function will panic if `self` is less than or equal to zero. /// /// # Examples /// @@ -2330,24 +2320,14 @@ macro_rules! int_impl { #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] pub const fn ilog2(self) -> u32 { - match self.checked_ilog2() { - Some(n) => n, - None => { - // In debug builds, trigger a panic on None. - // This should optimize completely out in release builds. - let _ = Self::MAX + 1; - - 0 - }, - } + self.checked_ilog2().expect("argument of integer logarithm must be positive") } /// Returns the base 10 logarithm of the number, rounded down. /// /// # Panics /// - /// When the number is negative or zero it panics in debug mode and the return value - /// is 0 in release mode. + /// This function will panic if `self` is less than or equal to zero. /// /// # Example /// @@ -2363,16 +2343,7 @@ macro_rules! int_impl { #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] pub const fn ilog10(self) -> u32 { - match self.checked_ilog10() { - Some(n) => n, - None => { - // In debug builds, trigger a panic on None. - // This should optimize completely out in release builds. - let _ = Self::MAX + 1; - - 0 - }, - } + self.checked_ilog10().expect("argument of integer logarithm must be positive") } /// Returns the logarithm of the number with respect to an arbitrary base, diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 46b0ca2303406..83836f2a3954b 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -692,8 +692,7 @@ macro_rules! uint_impl { /// /// # Panics /// - /// When the number is zero, or if the base is not at least 2; - /// it panics in debug mode and the return value is 0 in release mode. + /// This function will panic if `self` is zero, or if `base` is less then 2. /// /// # Examples /// @@ -709,24 +708,15 @@ macro_rules! uint_impl { #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] pub const fn ilog(self, base: Self) -> u32 { - match self.checked_ilog(base) { - Some(n) => n, - None => { - // In debug builds, trigger a panic on None. - // This should optimize completely out in release builds. - let _ = Self::MAX + 1; - - 0 - }, - } + assert!(base >= 2, "base of integer logarithm must be at least 2"); + self.checked_ilog(base).expect("argument of integer logarithm must be positive") } /// Returns the base 2 logarithm of the number, rounded down. /// /// # Panics /// - /// When the number is zero it panics in debug mode and - /// the return value is 0 in release mode. + /// This function will panic if `self` is zero. /// /// # Examples /// @@ -742,24 +732,14 @@ macro_rules! uint_impl { #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] pub const fn ilog2(self) -> u32 { - match self.checked_ilog2() { - Some(n) => n, - None => { - // In debug builds, trigger a panic on None. - // This should optimize completely out in release builds. - let _ = Self::MAX + 1; - - 0 - }, - } + self.checked_ilog2().expect("argument of integer logarithm must be positive") } /// Returns the base 10 logarithm of the number, rounded down. /// /// # Panics /// - /// When the number is zero it panics in debug mode and the - /// return value is 0 in release mode. + /// This function will panic if `self` is zero. /// /// # Example /// @@ -775,16 +755,7 @@ macro_rules! uint_impl { #[rustc_inherit_overflow_checks] #[allow(arithmetic_overflow)] pub const fn ilog10(self) -> u32 { - match self.checked_ilog10() { - Some(n) => n, - None => { - // In debug builds, trigger a panic on None. - // This should optimize completely out in release builds. - let _ = Self::MAX + 1; - - 0 - }, - } + self.checked_ilog10().expect("argument of integer logarithm must be positive") } /// Returns the logarithm of the number with respect to an arbitrary base, From 6acc29f88b2fdf7a048fae77b031b803f86e1551 Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 2 Oct 2022 14:25:36 +0200 Subject: [PATCH 08/43] add tests for panicking integer logarithms --- library/core/tests/num/int_log.rs | 30 ++++++++++++++++++++++++++++++ 1 file changed, 30 insertions(+) diff --git a/library/core/tests/num/int_log.rs b/library/core/tests/num/int_log.rs index be203fb5c04ff..a1edb1a518632 100644 --- a/library/core/tests/num/int_log.rs +++ b/library/core/tests/num/int_log.rs @@ -164,3 +164,33 @@ fn ilog10_u64() { fn ilog10_u128() { ilog10_loop! { u128, 38 } } + +#[test] +#[should_panic(expected = "argument of integer logarithm must be positive")] +fn ilog2_of_0_panic() { + let _ = 0u32.ilog2(); +} + +#[test] +#[should_panic(expected = "argument of integer logarithm must be positive")] +fn ilog10_of_0_panic() { + let _ = 0u32.ilog10(); +} + +#[test] +#[should_panic(expected = "argument of integer logarithm must be positive")] +fn ilog3_of_0_panic() { + let _ = 0u32.ilog(3); +} + +#[test] +#[should_panic(expected = "base of integer logarithm must be at least 2")] +fn ilog0_of_1_panic() { + let _ = 1u32.ilog(0); +} + +#[test] +#[should_panic(expected = "base of integer logarithm must be at least 2")] +fn ilog1_of_1_panic() { + let _ = 1u32.ilog(1); +} From b7dae8a5e2ad75ca8f472c953f459c45e019896d Mon Sep 17 00:00:00 2001 From: Lukas Markeffsky <@> Date: Sun, 2 Oct 2022 15:15:40 +0200 Subject: [PATCH 09/43] remove unneeded attributes --- library/core/src/num/int_macros.rs | 6 ------ library/core/src/num/uint_macros.rs | 6 ------ 2 files changed, 12 deletions(-) diff --git a/library/core/src/num/int_macros.rs b/library/core/src/num/int_macros.rs index 4eb85a281e20d..ff3b7bc2c9047 100644 --- a/library/core/src/num/int_macros.rs +++ b/library/core/src/num/int_macros.rs @@ -2293,8 +2293,6 @@ macro_rules! int_impl { without modifying the original"] #[inline] #[track_caller] - #[rustc_inherit_overflow_checks] - #[allow(arithmetic_overflow)] pub const fn ilog(self, base: Self) -> u32 { assert!(base >= 2, "base of integer logarithm must be at least 2"); self.checked_ilog(base).expect("argument of integer logarithm must be positive") @@ -2317,8 +2315,6 @@ macro_rules! int_impl { without modifying the original"] #[inline] #[track_caller] - #[rustc_inherit_overflow_checks] - #[allow(arithmetic_overflow)] pub const fn ilog2(self) -> u32 { self.checked_ilog2().expect("argument of integer logarithm must be positive") } @@ -2340,8 +2336,6 @@ macro_rules! int_impl { without modifying the original"] #[inline] #[track_caller] - #[rustc_inherit_overflow_checks] - #[allow(arithmetic_overflow)] pub const fn ilog10(self) -> u32 { self.checked_ilog10().expect("argument of integer logarithm must be positive") } diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index 83836f2a3954b..d921ff9ba1026 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -705,8 +705,6 @@ macro_rules! uint_impl { without modifying the original"] #[inline] #[track_caller] - #[rustc_inherit_overflow_checks] - #[allow(arithmetic_overflow)] pub const fn ilog(self, base: Self) -> u32 { assert!(base >= 2, "base of integer logarithm must be at least 2"); self.checked_ilog(base).expect("argument of integer logarithm must be positive") @@ -729,8 +727,6 @@ macro_rules! uint_impl { without modifying the original"] #[inline] #[track_caller] - #[rustc_inherit_overflow_checks] - #[allow(arithmetic_overflow)] pub const fn ilog2(self) -> u32 { self.checked_ilog2().expect("argument of integer logarithm must be positive") } @@ -752,8 +748,6 @@ macro_rules! uint_impl { without modifying the original"] #[inline] #[track_caller] - #[rustc_inherit_overflow_checks] - #[allow(arithmetic_overflow)] pub const fn ilog10(self) -> u32 { self.checked_ilog10().expect("argument of integer logarithm must be positive") } From bde80f745b86750a31294013fef590dd9e6965c3 Mon Sep 17 00:00:00 2001 From: rdvdev2 Date: Mon, 22 Aug 2022 08:56:46 +0200 Subject: [PATCH 10/43] Add lint for diagnostic migration --- compiler/rustc_passes/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 6e621b7eb5eb0..15f60f626c89a 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -5,6 +5,8 @@ //! This API is completely unstable and subject to change. #![allow(rustc::potential_query_instability)] +#![deny(rustc::untranslatable_diagnostic)] +#![deny(rustc::diagnostic_outside_of_impl)] #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(iter_intersperse)] #![feature(let_chains)] From 2f74d1d14ff08bfc5995ba1379840e5bd3f30efb Mon Sep 17 00:00:00 2001 From: rdvdev2 Date: Mon, 22 Aug 2022 10:05:13 +0200 Subject: [PATCH 11/43] Migrate weak_lang_items.rs --- .../locales/en-US/passes.ftl | 9 +++++++++ compiler/rustc_passes/src/errors.rs | 17 +++++++++++++++++ compiler/rustc_passes/src/weak_lang_items.rs | 15 +++++---------- 3 files changed, 31 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 995ad4fe25859..bfe22727483da 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -271,3 +271,12 @@ passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect .suggestion = remove the unnecessary deprecation attribute + +passes_missing_panic_handler = `#[panic_handler]` function required, but not found + +passes_missing_alloc_error_handler = `#[alloc_error_handler]` function required, but not found + .note = use `#![feature(default_alloc_error_handler)]` for a default error handler + +passes_missing_lang_item = language item required, but not found: `{$name}` + .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library + .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config` diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index cc231af71a274..7dbdee8a87ae5 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -665,3 +665,20 @@ pub struct DeprecatedAnnotationHasNoEffect { #[suggestion(applicability = "machine-applicable", code = "")] pub span: Span, } + +#[derive(Diagnostic)] +#[diag(passes::missing_panic_handler)] +pub struct MissingPanicHandler; + +#[derive(Diagnostic)] +#[diag(passes::missing_alloc_error_handler)] +#[note] +pub struct MissingAllocErrorHandler; + +#[derive(Diagnostic)] +#[diag(passes::missing_lang_item)] +#[note] +#[help] +pub struct MissingLangItem { + pub name: Symbol, +} diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index c48b4ecf87a3a..2345de74bdfbc 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -8,6 +8,8 @@ use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; +use crate::errors::{MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler}; + /// Checks the crate for usage of weak lang items, returning a vector of all the /// language items required by this crate, but not defined yet. pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItems) { @@ -71,20 +73,13 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { for (name, &item) in WEAK_ITEMS_REFS.iter() { if missing.contains(&item) && required(tcx, item) && items.require(item).is_err() { if item == LangItem::PanicImpl { - tcx.sess.err("`#[panic_handler]` function required, but not found"); + tcx.sess.emit_err(MissingPanicHandler); } else if item == LangItem::Oom { if !tcx.features().default_alloc_error_handler { - tcx.sess.err("`#[alloc_error_handler]` function required, but not found"); - tcx.sess.note_without_error("use `#![feature(default_alloc_error_handler)]` for a default error handler"); + tcx.sess.emit_err(MissingAllocErrorHandler); } } else { - tcx - .sess - .diagnostic() - .struct_err(&format!("language item required, but not found: `{}`", name)) - .note(&format!("this can occur when a binary crate with `#![no_std]` is compiled for a target where `{}` is defined in the standard library", name)) - .help(&format!("you may be able to compile for a target that doesn't need `{}`, specify a target with `--target` or in `.cargo/config`", name)) - .emit(); + tcx.sess.emit_err(MissingLangItem { name: *name }); } } } From 17a4a68ab0ffa0e8736d5ccf71f6e56794a0320a Mon Sep 17 00:00:00 2001 From: rdvdev2 Date: Fri, 2 Sep 2022 00:11:44 +0200 Subject: [PATCH 12/43] Migrate derivable diagnostics in lang_items.rs --- .../locales/en-US/passes.ftl | 8 +++++ compiler/rustc_passes/src/errors.rs | 21 +++++++++++++ compiler/rustc_passes/src/lang_items.rs | 30 +++++-------------- 3 files changed, 37 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index bfe22727483da..6512af1d14c86 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -280,3 +280,11 @@ passes_missing_alloc_error_handler = `#[alloc_error_handler]` function required, passes_missing_lang_item = language item required, but not found: `{$name}` .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config` + +passes_lang_item_on_incorrect_target = `{$name}` language item must be applied to a {$expected_target} + .label = attribute should be applied to a {$expected_target}, not a {$actual_target} + +passes_unknown_lang_item = definition of an unknown language item: `{$name}` + .label = definition of unknown language item `{$name}` + +passes_local_duplicate_lang_item = found duplicate lang item `{$name}` diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 7dbdee8a87ae5..cd05784cd53b3 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,4 +1,5 @@ use rustc_errors::{Applicability, MultiSpan}; +use rustc_hir::Target; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -682,3 +683,23 @@ pub struct MissingAllocErrorHandler; pub struct MissingLangItem { pub name: Symbol, } + +#[derive(Diagnostic)] +#[diag(passes::lang_item_on_incorrect_target, code = "E0718")] +pub struct LangItemOnIncorrectTarget { + #[primary_span] + #[label] + pub span: Span, + pub name: Symbol, + pub expected_target: Target, + pub actual_target: Target, +} + +#[derive(Diagnostic)] +#[diag(passes::unknown_lang_item, code = "E0522")] +pub struct UnknownLangItem { + #[primary_span] + #[label] + pub span: Span, + pub name: Symbol, +} diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 79900a90aed63..98ff625d09469 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -7,6 +7,7 @@ //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Functions called by the compiler itself. +use crate::errors::{LangItemOnIncorrectTarget, UnknownLangItem}; use crate::check_attr::target_from_impl_item; use crate::weak_lang_items; @@ -42,34 +43,19 @@ impl<'tcx> LanguageItemCollector<'tcx> { } // Known lang item with attribute on incorrect target. Some((_, expected_target)) => { - struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(LangItemOnIncorrectTarget { span, - E0718, - "`{}` language item must be applied to a {}", - value, + name: value, expected_target, - ) - .span_label( - span, - format!( - "attribute should be applied to a {}, not a {}", - expected_target, actual_target, - ), - ) - .emit(); + actual_target, + }); } // Unknown lang item. _ => { - struct_span_err!( - self.tcx.sess, + self.tcx.sess.emit_err(UnknownLangItem { span, - E0522, - "definition of an unknown language item: `{}`", - value - ) - .span_label(span, format!("definition of unknown language item `{}`", value)) - .emit(); + name: value, + }); } } } From 0315d7c9dbc33164ce8d1a7ad0464fa695a59399 Mon Sep 17 00:00:00 2001 From: rdvdev2 Date: Fri, 2 Sep 2022 04:54:42 +0200 Subject: [PATCH 13/43] Migrate derivable diagnostics in check_attr.rs --- .../rustc_error_messages/locales/en-US/passes.ftl | 2 ++ compiler/rustc_passes/src/check_attr.rs | 14 ++++++-------- compiler/rustc_passes/src/errors.rs | 11 +++++++++++ 3 files changed, 19 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 6512af1d14c86..9a3ea51c778df 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -217,6 +217,8 @@ passes_debug_visualizer_invalid = invalid argument .note_2 = OR .note_3 = expected: `gdb_script_file = "..."` +passes_debug_visualizer_unreadable = couldn't read {$file}: {$error} + passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn` .label = not a `const fn` diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 87433538512b9..864ce751588f1 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -4,7 +4,7 @@ //! conflicts between multiple such attributes attached to the same //! item. -use crate::errors; +use crate::errors::{self, DebugVisualizerUnreadable}; use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan}; @@ -1863,13 +1863,11 @@ impl CheckAttrVisitor<'_> { match std::fs::File::open(&file) { Ok(_) => true, Err(err) => { - self.tcx - .sess - .struct_span_err( - meta_item.span, - &format!("couldn't read {}: {}", file.display(), err), - ) - .emit(); + self.tcx.sess.emit_err(DebugVisualizerUnreadable { + span: meta_item.span, + file: &file, + error: err, + } ); false } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index cd05784cd53b3..5730e9db66685 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,3 +1,5 @@ +use std::{io::Error, path::Path}; + use rustc_errors::{Applicability, MultiSpan}; use rustc_hir::Target; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; @@ -527,6 +529,15 @@ pub struct DebugVisualizerInvalid { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes::debug_visualizer_unreadable)] +pub struct DebugVisualizerUnreadable<'a> { + #[primary_span] + pub span: Span, + pub file: &'a Path, + pub error: Error, +} + #[derive(Diagnostic)] #[diag(passes::rustc_allow_const_fn_unstable)] pub struct RustcAllowConstFnUnstable { From 2c3351c9a64caf76775c1335201a4762f5fdeaf8 Mon Sep 17 00:00:00 2001 From: rdvdev2 Date: Fri, 2 Sep 2022 05:19:03 +0200 Subject: [PATCH 14/43] Migrate InvalidAttrAtCrateLevel Co-authored-by: Nathan Stocks Co-authored-by: rdvdev2 --- .../locales/en-US/passes.ftl | 3 ++ compiler/rustc_passes/src/check_attr.rs | 28 ++++------------ compiler/rustc_passes/src/errors.rs | 32 ++++++++++++++++++- compiler/rustc_passes/src/lang_items.rs | 7 ++-- 4 files changed, 43 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 9a3ea51c778df..c1c2f379fa52a 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -290,3 +290,6 @@ passes_unknown_lang_item = definition of an unknown language item: `{$name}` .label = definition of unknown language item `{$name}` passes_local_duplicate_lang_item = found duplicate lang item `{$name}` + +passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level + .suggestion = perhaps you meant to use an outer attribute diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 864ce751588f1..2a9578e8ce32c 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -4,7 +4,7 @@ //! conflicts between multiple such attributes attached to the same //! item. -use crate::errors::{self, DebugVisualizerUnreadable}; +use crate::errors::{self, DebugVisualizerUnreadable, InvalidAttrAtCrateLevel}; use rustc_ast::{ast, AttrStyle, Attribute, Lit, LitKind, MetaItemKind, NestedMetaItem}; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{fluent, struct_span_err, Applicability, MultiSpan}; @@ -1867,7 +1867,7 @@ impl CheckAttrVisitor<'_> { span: meta_item.span, file: &file, error: err, - } ); + }); false } } @@ -2178,25 +2178,11 @@ fn check_invalid_crate_level_attr(tcx: TyCtxt<'_>, attrs: &[Attribute]) { if attr.style == AttrStyle::Inner { for attr_to_check in ATTRS_TO_CHECK { if attr.has_name(*attr_to_check) { - let mut err = tcx.sess.struct_span_err( - attr.span, - &format!( - "`{}` attribute cannot be used at crate level", - attr_to_check.to_ident_string() - ), - ); - // Only emit an error with a suggestion if we can create a - // string out of the attribute span - if let Ok(src) = tcx.sess.source_map().span_to_snippet(attr.span) { - let replacement = src.replace("#!", "#"); - err.span_suggestion_verbose( - attr.span, - "perhaps you meant to use an outer attribute", - replacement, - rustc_errors::Applicability::MachineApplicable, - ); - } - err.emit(); + tcx.sess.emit_err(InvalidAttrAtCrateLevel { + span: attr.span, + snippet: tcx.sess.source_map().span_to_snippet(attr.span).ok(), + name: *attr_to_check, + }); } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 5730e9db66685..9b8eebd6be0be 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,6 +1,6 @@ use std::{io::Error, path::Path}; -use rustc_errors::{Applicability, MultiSpan}; +use rustc_errors::{Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; use rustc_hir::Target; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -714,3 +714,33 @@ pub struct UnknownLangItem { pub span: Span, pub name: Symbol, } + +pub struct InvalidAttrAtCrateLevel { + pub span: Span, + pub snippet: Option, + pub name: Symbol, +} + +impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { + fn into_diagnostic( + self, + handler: &'_ rustc_errors::Handler, + ) -> rustc_errors::DiagnosticBuilder<'_, ErrorGuaranteed> { + let mut diag = + handler.struct_err(rustc_errors::fluent::passes::invalid_attr_at_crate_level); + diag.set_span(self.span); + diag.set_arg("name", self.name); + // Only emit an error with a suggestion if we can create a string out + // of the attribute span + if let Some(src) = self.snippet { + let replacement = src.replace("#!", "#"); + diag.span_suggestion_verbose( + self.span, + rustc_errors::fluent::passes::suggestion, + replacement, + rustc_errors::Applicability::MachineApplicable, + ); + } + diag + } +} diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 98ff625d09469..24657372486f2 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -7,8 +7,8 @@ //! * Traits that represent operators; e.g., `Add`, `Sub`, `Index`. //! * Functions called by the compiler itself. -use crate::errors::{LangItemOnIncorrectTarget, UnknownLangItem}; use crate::check_attr::target_from_impl_item; +use crate::errors::{LangItemOnIncorrectTarget, UnknownLangItem}; use crate::weak_lang_items; use rustc_errors::{pluralize, struct_span_err}; @@ -52,10 +52,7 @@ impl<'tcx> LanguageItemCollector<'tcx> { } // Unknown lang item. _ => { - self.tcx.sess.emit_err(UnknownLangItem { - span, - name: value, - }); + self.tcx.sess.emit_err(UnknownLangItem { span, name: value }); } } } From c24a87315af884680332f850753b3eeef18c22c8 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Wed, 21 Sep 2022 14:05:15 -0600 Subject: [PATCH 15/43] always put ftl message on next line, resolve all but 1 output comparison error --- .../locales/en-US/passes.ftl | 269 ++++++++++++------ 1 file changed, 180 insertions(+), 89 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index c1c2f379fa52a..bd6a973e9163f 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -10,88 +10,119 @@ passes_outer_crate_level_attr = passes_inner_crate_level_attr = crate-level attribute should be in the root module -passes_ignored_attr_with_macro = `#[{$sym}]` is ignored on struct fields, match arms and macro defs +passes_ignored_attr_with_macro = + `#[{$sym}]` is ignored on struct fields, match arms and macro defs .warn = {-passes_previously_accepted} .note = {-passes_see_issue(issue: "80564")} -passes_ignored_attr = `#[{$sym}]` is ignored on struct fields and match arms +passes_ignored_attr = + `#[{$sym}]` is ignored on struct fields and match arms .warn = {-passes_previously_accepted} .note = {-passes_see_issue(issue: "80564")} -passes_inline_ignored_function_prototype = `#[inline]` is ignored on function prototypes +passes_inline_ignored_function_prototype = + `#[inline]` is ignored on function prototypes -passes_inline_ignored_constants = `#[inline]` is ignored on constants +passes_inline_ignored_constants = + `#[inline]` is ignored on constants .warn = {-passes_previously_accepted} .note = {-passes_see_issue(issue: "65833")} -passes_inline_not_fn_or_closure = attribute should be applied to function or closure +passes_inline_not_fn_or_closure = + attribute should be applied to function or closure .label = not a function or closure -passes_no_coverage_ignored_function_prototype = `#[no_coverage]` is ignored on function prototypes +passes_no_coverage_ignored_function_prototype = + `#[no_coverage]` is ignored on function prototypes passes_no_coverage_propagate = `#[no_coverage]` does not propagate into items and must be applied to the contained functions directly -passes_no_coverage_fn_defn = `#[no_coverage]` may only be applied to function definitions +passes_no_coverage_fn_defn = + `#[no_coverage]` may only be applied to function definitions -passes_no_coverage_not_coverable = `#[no_coverage]` must be applied to coverable code +passes_no_coverage_not_coverable = + `#[no_coverage]` must be applied to coverable code .label = not coverable code -passes_should_be_applied_to_fn = attribute should be applied to a function definition +passes_should_be_applied_to_fn = + attribute should be applied to a function definition .label = not a function definition -passes_naked_tracked_caller = cannot use `#[track_caller]` with `#[naked]` +passes_naked_tracked_caller = + cannot use `#[track_caller]` with `#[naked]` -passes_should_be_applied_to_struct_enum = attribute should be applied to a struct or enum +passes_should_be_applied_to_struct_enum = + attribute should be applied to a struct or enum .label = not a struct or enum -passes_should_be_applied_to_trait = attribute should be applied to a trait +passes_should_be_applied_to_trait = + attribute should be applied to a trait .label = not a trait -passes_target_feature_on_statement = {passes_should_be_applied_to_fn} +passes_target_feature_on_statement = + {passes_should_be_applied_to_fn} .warn = {-passes_previously_accepted} .label = {passes_should_be_applied_to_fn.label} -passes_should_be_applied_to_static = attribute should be applied to a static +passes_should_be_applied_to_static = + attribute should be applied to a static .label = not a static -passes_doc_expect_str = doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] +passes_doc_expect_str = + doc {$attr_name} attribute expects a string: #[doc({$attr_name} = "a")] -passes_doc_alias_empty = {$attr_str} attribute cannot have empty value +passes_doc_alias_empty = + {$attr_str} attribute cannot have empty value -passes_doc_alias_bad_char = {$char_} character isn't allowed in {$attr_str} +passes_doc_alias_bad_char = + {$char_} character isn't allowed in {$attr_str} -passes_doc_alias_start_end = {$attr_str} cannot start or end with ' ' +passes_doc_alias_start_end = + {$attr_str} cannot start or end with ' ' -passes_doc_alias_bad_location = {$attr_str} isn't allowed on {$location} +passes_doc_alias_bad_location = + {$attr_str} isn't allowed on {$location} -passes_doc_alias_not_an_alias = {$attr_str} is the same as the item's name +passes_doc_alias_not_an_alias = + {$attr_str} is the same as the item's name passes_doc_alias_duplicated = doc alias is duplicated .label = first defined here -passes_doc_alias_not_string_literal = `#[doc(alias("a"))]` expects string literals +passes_doc_alias_not_string_literal = + `#[doc(alias("a"))]` expects string literals passes_doc_alias_malformed = doc alias attribute expects a string `#[doc(alias = "a")]` or a list of strings `#[doc(alias("a", "b"))]` -passes_doc_keyword_empty_mod = `#[doc(keyword = "...")]` should be used on empty modules +passes_doc_keyword_empty_mod = + `#[doc(keyword = "...")]` should be used on empty modules -passes_doc_keyword_not_mod = `#[doc(keyword = "...")]` should be used on modules +passes_doc_keyword_not_mod = + `#[doc(keyword = "...")]` should be used on modules -passes_doc_keyword_invalid_ident = `{$doc_keyword}` is not a valid identifier +passes_doc_keyword_invalid_ident = + `{$doc_keyword}` is not a valid identifier passes_doc_fake_variadic_not_valid = `#[doc(fake_variadic)]` must be used on the first of a set of tuple or fn pointer trait impls with varying arity -passes_doc_keyword_only_impl = `#[doc(keyword = "...")]` should be used on impl blocks +passes_doc_keyword_only_impl = + `#[doc(keyword = "...")]` should be used on impl blocks -passes_doc_inline_conflict_first = this attribute... -passes_doc_inline_conflict_second = ...conflicts with this attribute -passes_doc_inline_conflict = conflicting doc inlining attributes +passes_doc_inline_conflict_first = + this attribute... + +passes_doc_inline_conflict_second = + {"."}..conflicts with this attribute + +passes_doc_inline_conflict = + conflicting doc inlining attributes .help = remove one of the conflicting attributes -passes_doc_inline_only_use = this attribute can only be applied to a `use` item +passes_doc_inline_only_use = + this attribute can only be applied to a `use` item .label = only applicable on `use` items .not_a_use_item_label = not a `use` item .note = read for more information @@ -99,30 +130,39 @@ passes_doc_inline_only_use = this attribute can only be applied to a `use` item passes_doc_attr_not_crate_level = `#![doc({$attr_name} = "...")]` isn't allowed as a crate-level attribute -passes_attr_crate_level = this attribute can only be applied at the crate level +passes_attr_crate_level = + this attribute can only be applied at the crate level .suggestion = to apply to the crate, use an inner attribute .help = to apply to the crate, use an inner attribute .note = read for more information -passes_doc_test_unknown = unknown `doc(test)` attribute `{$path}` +passes_doc_test_unknown = + unknown `doc(test)` attribute `{$path}` -passes_doc_test_takes_list = `#[doc(test(...)]` takes a list of attributes +passes_doc_test_takes_list = + `#[doc(test(...)]` takes a list of attributes -passes_doc_primitive = `doc(primitive)` should never have been stable +passes_doc_primitive = + `doc(primitive)` should never have been stable -passes_doc_test_unknown_any = unknown `doc` attribute `{$path}` +passes_doc_test_unknown_any = + unknown `doc` attribute `{$path}` -passes_doc_test_unknown_spotlight = unknown `doc` attribute `{$path}` +passes_doc_test_unknown_spotlight = + unknown `doc` attribute `{$path}` .note = `doc(spotlight)` was renamed to `doc(notable_trait)` .suggestion = use `notable_trait` instead .no_op_note = `doc(spotlight)` is now a no-op -passes_doc_test_unknown_include = unknown `doc` attribute `{$path}` +passes_doc_test_unknown_include = + unknown `doc` attribute `{$path}` .suggestion = use `doc = include_str!` instead -passes_doc_invalid = invalid `doc` attribute +passes_doc_invalid = + invalid `doc` attribute -passes_pass_by_value = `pass_by_value` attribute should be applied to a struct, enum or type alias +passes_pass_by_value = + `pass_by_value` attribute should be applied to a struct, enum or type alias .label = is not a struct, enum or type alias passes_allow_incoherent_impl = @@ -137,42 +177,54 @@ passes_must_use_async = `must_use` attribute on `async` functions applies to the anonymous `Future` returned by the function, not the value within .label = this attribute does nothing, the `Future`s returned by async functions are already `must_use` -passes_must_use_no_effect = `#[must_use]` has no effect when applied to {$article} {$target} +passes_must_use_no_effect = + `#[must_use]` has no effect when applied to {$article} {$target} -passes_must_not_suspend = `must_not_suspend` attribute should be applied to a struct, enum, or trait +passes_must_not_suspend = + `must_not_suspend` attribute should be applied to a struct, enum, or trait .label = is not a struct, enum, or trait -passes_cold = {passes_should_be_applied_to_fn} +passes_cold = + {passes_should_be_applied_to_fn} .warn = {-passes_previously_accepted} .label = {passes_should_be_applied_to_fn.label} -passes_link = attribute should be applied to an `extern` block with non-Rust ABI +passes_link = + attribute should be applied to an `extern` block with non-Rust ABI .warn = {-passes_previously_accepted} .label = not an `extern` block -passes_link_name = attribute should be applied to a foreign function or static +passes_link_name = + attribute should be applied to a foreign function or static .warn = {-passes_previously_accepted} .label = not a foreign function or static .help = try `#[link(name = "{$value}")]` instead -passes_no_link = attribute should be applied to an `extern crate` item +passes_no_link = + attribute should be applied to an `extern crate` item .label = not an `extern crate` item -passes_export_name = attribute should be applied to a free function, impl method or static +passes_export_name = + attribute should be applied to a free function, impl method or static .label = not a free function, impl method or static -passes_rustc_layout_scalar_valid_range_not_struct = attribute should be applied to a struct +passes_rustc_layout_scalar_valid_range_not_struct = + attribute should be applied to a struct .label = not a struct -passes_rustc_layout_scalar_valid_range_arg = expected exactly one integer literal argument +passes_rustc_layout_scalar_valid_range_arg = + expected exactly one integer literal argument -passes_rustc_legacy_const_generics_only = #[rustc_legacy_const_generics] functions must only have const generics +passes_rustc_legacy_const_generics_only = + #[rustc_legacy_const_generics] functions must only have const generics .label = non-const generic parameter -passes_rustc_legacy_const_generics_index = #[rustc_legacy_const_generics] must have one index for each generic parameter +passes_rustc_legacy_const_generics_index = + #[rustc_legacy_const_generics] must have one index for each generic parameter .label = generic parameters -passes_rustc_legacy_const_generics_index_exceed = index exceeds number of arguments +passes_rustc_legacy_const_generics_index_exceed = + index exceeds number of arguments .label = there {$arg_count -> [one] is *[other] are @@ -181,115 +233,154 @@ passes_rustc_legacy_const_generics_index_exceed = index exceeds number of argume *[other] arguments } -passes_rustc_legacy_const_generics_index_negative = arguments should be non-negative integers +passes_rustc_legacy_const_generics_index_negative = + arguments should be non-negative integers -passes_rustc_dirty_clean = attribute requires -Z query-dep-graph to be enabled +passes_rustc_dirty_clean = + attribute requires -Z query-dep-graph to be enabled -passes_link_section = attribute should be applied to a function or static +passes_link_section = + attribute should be applied to a function or static .warn = {-passes_previously_accepted} .label = not a function or static -passes_no_mangle_foreign = `#[no_mangle]` has no effect on a foreign {$foreign_item_kind} +passes_no_mangle_foreign = + `#[no_mangle]` has no effect on a foreign {$foreign_item_kind} .warn = {-passes_previously_accepted} .label = foreign {$foreign_item_kind} .note = symbol names in extern blocks are not mangled .suggestion = remove this attribute -passes_no_mangle = attribute should be applied to a free function, impl method or static +passes_no_mangle = + attribute should be applied to a free function, impl method or static .warn = {-passes_previously_accepted} .label = not a free function, impl method or static -passes_repr_ident = meta item in `repr` must be an identifier +passes_repr_ident = + meta item in `repr` must be an identifier -passes_repr_conflicting = conflicting representation hints +passes_repr_conflicting = + conflicting representation hints -passes_used_static = attribute must be applied to a `static` variable +passes_used_static = + attribute must be applied to a `static` variable -passes_used_compiler_linker = `used(compiler)` and `used(linker)` can't be used together +passes_used_compiler_linker = + `used(compiler)` and `used(linker)` can't be used together -passes_allow_internal_unstable = attribute should be applied to a macro +passes_allow_internal_unstable = + attribute should be applied to a macro .label = not a macro -passes_debug_visualizer_placement = attribute should be applied to a module +passes_debug_visualizer_placement = + attribute should be applied to a module -passes_debug_visualizer_invalid = invalid argument +passes_debug_visualizer_invalid = + invalid argument .note_1 = expected: `natvis_file = "..."` .note_2 = OR .note_3 = expected: `gdb_script_file = "..."` -passes_debug_visualizer_unreadable = couldn't read {$file}: {$error} +passes_debug_visualizer_unreadable = + couldn't read {$file}: {$error} -passes_rustc_allow_const_fn_unstable = attribute should be applied to `const fn` +passes_rustc_allow_const_fn_unstable = + attribute should be applied to `const fn` .label = not a `const fn` -passes_rustc_std_internal_symbol = attribute should be applied to functions or statics +passes_rustc_std_internal_symbol = + attribute should be applied to functions or statics .label = not a function or static -passes_const_trait = attribute should be applied to a trait +passes_const_trait = + attribute should be applied to a trait -passes_stability_promotable = attribute cannot be applied to an expression +passes_stability_promotable = + attribute cannot be applied to an expression -passes_deprecated = attribute is ignored here +passes_deprecated = + attribute is ignored here -passes_macro_use = `#[{$name}]` only has an effect on `extern crate` and modules +passes_macro_use = + `#[{$name}]` only has an effect on `extern crate` and modules -passes_macro_export = `#[macro_export]` only has an effect on macro definitions +passes_macro_export = + `#[macro_export]` only has an effect on macro definitions -passes_plugin_registrar = `#[plugin_registrar]` only has an effect on functions +passes_plugin_registrar = + `#[plugin_registrar]` only has an effect on functions -passes_unused_empty_lints_note = attribute `{$name}` with an empty list has no effect +passes_unused_empty_lints_note = + attribute `{$name}` with an empty list has no effect -passes_unused_no_lints_note = attribute `{$name}` without any lints has no effect +passes_unused_no_lints_note = + attribute `{$name}` without any lints has no effect passes_unused_default_method_body_const_note = `default_method_body_is_const` has been replaced with `#[const_trait]` on traits -passes_unused = unused attribute +passes_unused = + unused attribute .suggestion = remove this attribute -passes_non_exported_macro_invalid_attrs = attribute should be applied to function or closure +passes_non_exported_macro_invalid_attrs = + attribute should be applied to function or closure .label = not a function or closure -passes_unused_duplicate = unused attribute +passes_unused_duplicate = + unused attribute .suggestion = remove this attribute .note = attribute also specified here .warn = {-passes_previously_accepted} -passes_unused_multiple = multiple `{$name}` attributes +passes_unused_multiple = + multiple `{$name}` attributes .suggestion = remove this attribute .note = attribute also specified here -passes_rustc_lint_opt_ty = `#[rustc_lint_opt_ty]` should be applied to a struct +passes_rustc_lint_opt_ty = + `#[rustc_lint_opt_ty]` should be applied to a struct .label = not a struct -passes_rustc_lint_opt_deny_field_access = `#[rustc_lint_opt_deny_field_access]` should be applied to a field +passes_rustc_lint_opt_deny_field_access = + `#[rustc_lint_opt_deny_field_access]` should be applied to a field .label = not a field -passes_link_ordinal = attribute should be applied to a foreign function or static +passes_link_ordinal = + attribute should be applied to a foreign function or static .label = not a foreign function or static -passes_collapse_debuginfo = `collapse_debuginfo` attribute should be applied to macro definitions +passes_collapse_debuginfo = + `collapse_debuginfo` attribute should be applied to macro definitions .label = not a macro definition -passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect +passes_deprecated_annotation_has_no_effect = + this `#[deprecated]` annotation has no effect .suggestion = remove the unnecessary deprecation attribute -passes_missing_panic_handler = `#[panic_handler]` function required, but not found +passes_missing_panic_handler = + `#[panic_handler]` function required, but not found -passes_missing_alloc_error_handler = `#[alloc_error_handler]` function required, but not found +passes_missing_alloc_error_handler = + `#[alloc_error_handler]` function required, but not found .note = use `#![feature(default_alloc_error_handler)]` for a default error handler -passes_missing_lang_item = language item required, but not found: `{$name}` +passes_missing_lang_item = + language item required, but not found: `{$name}` .note = this can occur when a binary crate with `#![no_std]` is compiled for a target where `{$name}` is defined in the standard library .help = you may be able to compile for a target that doesn't need `{$name}`, specify a target with `--target` or in `.cargo/config` -passes_lang_item_on_incorrect_target = `{$name}` language item must be applied to a {$expected_target} +passes_lang_item_on_incorrect_target = + `{$name}` language item must be applied to a {$expected_target} .label = attribute should be applied to a {$expected_target}, not a {$actual_target} -passes_unknown_lang_item = definition of an unknown language item: `{$name}` +passes_unknown_lang_item = + definition of an unknown language item: `{$name}` .label = definition of unknown language item `{$name}` -passes_local_duplicate_lang_item = found duplicate lang item `{$name}` +passes_local_duplicate_lang_item = + found duplicate lang item `{$name}` -passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level +passes_invalid_attr_at_crate_level = + `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute From b8e03cfa55d6133f8fc1fd3a82a7e686a9cf006e Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Wed, 21 Sep 2022 22:30:14 -0600 Subject: [PATCH 16/43] use consistent names --- compiler/rustc_passes/src/check_attr.rs | 4 ++-- compiler/rustc_passes/src/lang_items.rs | 8 ++++---- 2 files changed, 6 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_passes/src/check_attr.rs b/compiler/rustc_passes/src/check_attr.rs index 2a9578e8ce32c..18e1233fa84fd 100644 --- a/compiler/rustc_passes/src/check_attr.rs +++ b/compiler/rustc_passes/src/check_attr.rs @@ -1862,11 +1862,11 @@ impl CheckAttrVisitor<'_> { match std::fs::File::open(&file) { Ok(_) => true, - Err(err) => { + Err(error) => { self.tcx.sess.emit_err(DebugVisualizerUnreadable { span: meta_item.span, file: &file, - error: err, + error, }); false } diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index 24657372486f2..2b090e036fe99 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -35,8 +35,8 @@ impl<'tcx> LanguageItemCollector<'tcx> { fn check_for_lang(&mut self, actual_target: Target, hir_id: HirId) { let attrs = self.tcx.hir().attrs(hir_id); - if let Some((value, span)) = extract(&attrs) { - match ITEM_REFS.get(&value).cloned() { + if let Some((name, span)) = extract(&attrs) { + match ITEM_REFS.get(&name).cloned() { // Known lang item with attribute on correct target. Some((item_index, expected_target)) if actual_target == expected_target => { self.collect_item_extended(item_index, hir_id, span); @@ -45,14 +45,14 @@ impl<'tcx> LanguageItemCollector<'tcx> { Some((_, expected_target)) => { self.tcx.sess.emit_err(LangItemOnIncorrectTarget { span, - name: value, + name, expected_target, actual_target, }); } // Unknown lang item. _ => { - self.tcx.sess.emit_err(UnknownLangItem { span, name: value }); + self.tcx.sess.emit_err(UnknownLangItem { span, name }); } } } From 1222541cfd69386d0383c37042d8bbfd9f2ad0a3 Mon Sep 17 00:00:00 2001 From: Diego de Oliveira Date: Wed, 14 Sep 2022 15:03:12 -0300 Subject: [PATCH 17/43] resolve merge conflict from cherry-picking 6a47326a0452cc8d5cb57676508b5469d648c67f --- compiler/rustc_error_messages/locales/en-US/passes.ftl | 3 +++ compiler/rustc_passes/src/errors.rs | 7 +++++++ 2 files changed, 10 insertions(+) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index bd6a973e9163f..0c98f567276b4 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -384,3 +384,6 @@ passes_local_duplicate_lang_item = passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute + +passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect + .suggestion = remove the unnecessary deprecation attribute diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 9b8eebd6be0be..10deb4db55ffa 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -744,3 +744,10 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { diag } } + +#[derive(LintDiagnostic)] +#[diag(passes::deprecated_annotation_has_no_effect)] +pub struct DeprecatedAnnotationHasNoEffect { + #[suggestion(applicability = "machine-applicable", code = "")] + pub span: Span, +} From c103c3059f5481f60ae43465fce0646aa2c0dfa3 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Wed, 21 Sep 2022 22:49:30 -0600 Subject: [PATCH 18/43] migrate the rest of weak_lang_items.rs to translateable diagnostics --- .../rustc_error_messages/locales/en-US/passes.ftl | 6 +++--- compiler/rustc_passes/src/errors.rs | 15 ++++++++------- compiler/rustc_passes/src/weak_lang_items.rs | 14 ++++---------- 3 files changed, 15 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 0c98f567276b4..7dddc6e10b655 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -358,6 +358,9 @@ passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect .suggestion = remove the unnecessary deprecation attribute +passes_unknown_external_lang_item = + unknown external lang item: `{$lang_item}` + passes_missing_panic_handler = `#[panic_handler]` function required, but not found @@ -384,6 +387,3 @@ passes_local_duplicate_lang_item = passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute - -passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect - .suggestion = remove the unnecessary deprecation attribute diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 10deb4db55ffa..0fabbb206cf92 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -678,6 +678,14 @@ pub struct DeprecatedAnnotationHasNoEffect { pub span: Span, } +#[derive(Diagnostic)] +#[diag(passes::unknown_external_lang_item, code = "E0264")] +pub struct UnknownExternLangItem { + #[primary_span] + pub span: Span, + pub lang_item: Symbol, +} + #[derive(Diagnostic)] #[diag(passes::missing_panic_handler)] pub struct MissingPanicHandler; @@ -744,10 +752,3 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { diag } } - -#[derive(LintDiagnostic)] -#[diag(passes::deprecated_annotation_has_no_effect)] -pub struct DeprecatedAnnotationHasNoEffect { - #[suggestion(applicability = "machine-applicable", code = "")] - pub span: Span, -} diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 2345de74bdfbc..0d2745fb5f40f 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -1,14 +1,15 @@ //! Validity checking for weak lang items use rustc_data_structures::fx::FxHashSet; -use rustc_errors::struct_span_err; use rustc_hir::lang_items::{self, LangItem}; use rustc_hir::weak_lang_items::WEAK_ITEMS_REFS; use rustc_middle::middle::lang_items::required; use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; -use crate::errors::{MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler}; +use crate::errors::{ + MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler, UnknownExternLangItem, +}; /// Checks the crate for usage of weak lang items, returning a vector of all the /// language items required by this crate, but not defined yet. @@ -33,14 +34,7 @@ pub fn check_crate<'tcx>(tcx: TyCtxt<'tcx>, items: &mut lang_items::LanguageItem } } else { let span = tcx.def_span(id.def_id); - struct_span_err!( - tcx.sess, - span, - E0264, - "unknown external lang item: `{}`", - lang_item - ) - .emit(); + tcx.sess.emit_err(UnknownExternLangItem { span, lang_item }); } } } From 1e86226e9d6720b5c60c51d75b0a3f038d8bc5f5 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Wed, 21 Sep 2022 22:55:29 -0600 Subject: [PATCH 19/43] migrate debugger_visualizer.rs to translateable diagnostics --- compiler/rustc_passes/src/debugger_visualizer.rs | 15 ++++++++------- 1 file changed, 8 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_passes/src/debugger_visualizer.rs b/compiler/rustc_passes/src/debugger_visualizer.rs index e08683fe23b20..253b0a88e48aa 100644 --- a/compiler/rustc_passes/src/debugger_visualizer.rs +++ b/compiler/rustc_passes/src/debugger_visualizer.rs @@ -13,6 +13,8 @@ use rustc_span::{sym, DebuggerVisualizerFile, DebuggerVisualizerType}; use std::sync::Arc; +use crate::errors::DebugVisualizerUnreadable; + fn check_for_debugger_visualizer<'tcx>( tcx: TyCtxt<'tcx>, hir_id: HirId, @@ -54,13 +56,12 @@ fn check_for_debugger_visualizer<'tcx>( debugger_visualizers .insert(DebuggerVisualizerFile::new(Arc::from(contents), visualizer_type)); } - Err(err) => { - tcx.sess - .struct_span_err( - meta_item.span, - &format!("couldn't read {}: {}", file.display(), err), - ) - .emit(); + Err(error) => { + tcx.sess.emit_err(DebugVisualizerUnreadable { + span: meta_item.span, + file: &file, + error, + }); } } } From f8ebc72b4aa138772434039950126f2c7f07a3f4 Mon Sep 17 00:00:00 2001 From: David Wood Date: Thu, 1 Sep 2022 11:40:43 +0100 Subject: [PATCH 20/43] errors: add `emit_note`/`create_note` Add `Noted` marker struct that implements `EmissionGuarantee` so that `emit_note` and `create_note` can be implemented for struct diagnostics. Signed-off-by: David Wood --- .../rustc_errors/src/diagnostic_builder.rs | 50 +++++++++++++++++++ compiler/rustc_errors/src/lib.rs | 8 ++- compiler/rustc_session/src/parse.rs | 13 ++++- compiler/rustc_session/src/session.rs | 11 +++- 4 files changed, 78 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index bbe6435be59f4..9b41234dcfb66 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -255,6 +255,56 @@ impl EmissionGuarantee for () { } } +/// Marker type which enables implementation of `create_note` and `emit_note` functions for +/// note-without-error struct diagnostics. +#[derive(Copy, Clone)] +pub struct Noted; + +impl<'a> DiagnosticBuilder<'a, Noted> { + /// Convenience function for internal use, clients should use one of the + /// `struct_*` methods on [`Handler`]. + pub(crate) fn new_note(handler: &'a Handler, message: impl Into) -> Self { + let diagnostic = Diagnostic::new_with_code(Level::Note, None, message); + Self::new_diagnostic_note(handler, diagnostic) + } + + /// Creates a new `DiagnosticBuilder` with an already constructed + /// diagnostic. + pub(crate) fn new_diagnostic_note(handler: &'a Handler, diagnostic: Diagnostic) -> Self { + debug!("Created new diagnostic"); + Self { + inner: DiagnosticBuilderInner { + state: DiagnosticBuilderState::Emittable(handler), + diagnostic: Box::new(diagnostic), + }, + _marker: PhantomData, + } + } +} + +impl EmissionGuarantee for Noted { + fn diagnostic_builder_emit_producing_guarantee(db: &mut DiagnosticBuilder<'_, Self>) -> Self { + match db.inner.state { + // First `.emit()` call, the `&Handler` is still available. + DiagnosticBuilderState::Emittable(handler) => { + db.inner.state = DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation; + handler.emit_diagnostic(&mut db.inner.diagnostic); + } + // `.emit()` was previously called, disallowed from repeating it. + DiagnosticBuilderState::AlreadyEmittedOrDuringCancellation => {} + } + + Noted + } + + fn make_diagnostic_builder( + handler: &Handler, + msg: impl Into, + ) -> DiagnosticBuilder<'_, Self> { + DiagnosticBuilder::new_note(handler, msg) + } +} + impl<'a> DiagnosticBuilder<'a, !> { /// Convenience function for internal use, clients should use one of the /// `struct_*` methods on [`Handler`]. diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index 94a493992e593..a7fe280bc20ed 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -374,7 +374,7 @@ pub use diagnostic::{ AddToDiagnostic, DecorateLint, Diagnostic, DiagnosticArg, DiagnosticArgFromDisplay, DiagnosticArgValue, DiagnosticId, DiagnosticStyledString, IntoDiagnosticArg, SubDiagnostic, }; -pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee}; +pub use diagnostic_builder::{DiagnosticBuilder, EmissionGuarantee, Noted}; use std::backtrace::Backtrace; /// A handler deals with errors and other compiler output. @@ -988,7 +988,11 @@ impl Handler { } pub fn has_errors(&self) -> Option { - if self.inner.borrow().has_errors() { Some(ErrorGuaranteed(())) } else { None } + if self.inner.borrow().has_errors() { + Some(ErrorGuaranteed(())) + } else { + None + } } pub fn has_errors_or_lint_errors(&self) -> Option { if self.inner.borrow().has_errors_or_lint_errors() { diff --git a/compiler/rustc_session/src/parse.rs b/compiler/rustc_session/src/parse.rs index 2c3d8d5283b57..a199947ebed05 100644 --- a/compiler/rustc_session/src/parse.rs +++ b/compiler/rustc_session/src/parse.rs @@ -12,7 +12,7 @@ use rustc_data_structures::sync::{Lock, Lrc}; use rustc_errors::{emitter::SilentEmitter, ColorConfig, Handler}; use rustc_errors::{ fallback_fluent_bundle, Diagnostic, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, - EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, StashKey, + EmissionGuarantee, ErrorGuaranteed, IntoDiagnostic, MultiSpan, Noted, StashKey, }; use rustc_feature::{find_feature_issue, GateIssue, UnstableFeatures}; use rustc_span::edition::Edition; @@ -354,6 +354,17 @@ impl ParseSess { self.create_warning(warning).emit() } + pub fn create_note<'a>( + &'a self, + note: impl IntoDiagnostic<'a, Noted>, + ) -> DiagnosticBuilder<'a, Noted> { + note.into_diagnostic(&self.span_diagnostic) + } + + pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted { + self.create_note(note).emit() + } + pub fn create_fatal<'a>( &'a self, fatal: impl IntoDiagnostic<'a, !>, diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index 5926cdc9dad9a..beb22ab3eb951 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -28,7 +28,7 @@ use rustc_errors::json::JsonEmitter; use rustc_errors::registry::Registry; use rustc_errors::{ error_code, fallback_fluent_bundle, DiagnosticBuilder, DiagnosticId, DiagnosticMessage, - ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, + ErrorGuaranteed, FluentBundle, IntoDiagnostic, LazyFallbackBundle, MultiSpan, Noted, }; use rustc_macros::HashStable_Generic; pub use rustc_span::def_id::StableCrateId; @@ -489,6 +489,15 @@ impl Session { pub fn emit_warning<'a>(&'a self, warning: impl IntoDiagnostic<'a, ()>) { self.parse_sess.emit_warning(warning) } + pub fn create_note<'a>( + &'a self, + note: impl IntoDiagnostic<'a, Noted>, + ) -> DiagnosticBuilder<'a, Noted> { + self.parse_sess.create_note(note) + } + pub fn emit_note<'a>(&'a self, note: impl IntoDiagnostic<'a, Noted>) -> Noted { + self.parse_sess.emit_note(note) + } pub fn create_fatal<'a>( &'a self, fatal: impl IntoDiagnostic<'a, !>, From 3a748330af35ec9da4b07f55b78e8f08f2af0888 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 22 Sep 2022 10:15:51 -0600 Subject: [PATCH 21/43] use cherry-picked commit from #100754 to emit note without error --- compiler/rustc_error_messages/locales/en-US/passes.ftl | 6 ++++-- compiler/rustc_passes/src/errors.rs | 5 ++++- compiler/rustc_passes/src/weak_lang_items.rs | 6 ++++-- 3 files changed, 12 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 7dddc6e10b655..49cd2ee17588c 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -364,9 +364,11 @@ passes_unknown_external_lang_item = passes_missing_panic_handler = `#[panic_handler]` function required, but not found -passes_missing_alloc_error_handler = +passes_alloc_func_required = `#[alloc_error_handler]` function required, but not found - .note = use `#![feature(default_alloc_error_handler)]` for a default error handler + +passes_missing_alloc_error_handler = + use `#![feature(default_alloc_error_handler)]` for a default error handler passes_missing_lang_item = language item required, but not found: `{$name}` diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 0fabbb206cf92..26190af03587d 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -690,9 +690,12 @@ pub struct UnknownExternLangItem { #[diag(passes::missing_panic_handler)] pub struct MissingPanicHandler; +#[derive(Diagnostic)] +#[diag(passes::alloc_func_required)] +pub struct AllocFuncRequired; + #[derive(Diagnostic)] #[diag(passes::missing_alloc_error_handler)] -#[note] pub struct MissingAllocErrorHandler; #[derive(Diagnostic)] diff --git a/compiler/rustc_passes/src/weak_lang_items.rs b/compiler/rustc_passes/src/weak_lang_items.rs index 0d2745fb5f40f..92024989a75e2 100644 --- a/compiler/rustc_passes/src/weak_lang_items.rs +++ b/compiler/rustc_passes/src/weak_lang_items.rs @@ -8,7 +8,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::config::CrateType; use crate::errors::{ - MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler, UnknownExternLangItem, + AllocFuncRequired, MissingAllocErrorHandler, MissingLangItem, MissingPanicHandler, + UnknownExternLangItem, }; /// Checks the crate for usage of weak lang items, returning a vector of all the @@ -70,7 +71,8 @@ fn verify<'tcx>(tcx: TyCtxt<'tcx>, items: &lang_items::LanguageItems) { tcx.sess.emit_err(MissingPanicHandler); } else if item == LangItem::Oom { if !tcx.features().default_alloc_error_handler { - tcx.sess.emit_err(MissingAllocErrorHandler); + tcx.sess.emit_err(AllocFuncRequired); + tcx.sess.emit_note(MissingAllocErrorHandler); } } else { tcx.sess.emit_err(MissingLangItem { name: *name }); From 0609c0f1da13c8b0aeb90b5ff66f527bb16d58bf Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Thu, 22 Sep 2022 18:23:05 -0600 Subject: [PATCH 22/43] migrate diagnostic_items.rs to translateable diagnostics --- .../locales/en-US/passes.ftl | 12 ++++++- compiler/rustc_passes/src/diagnostic_items.rs | 36 +++++++++---------- compiler/rustc_passes/src/errors.rs | 20 +++++++++++ 3 files changed, 49 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 49cd2ee17588c..04fd0a3a6ac22 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -357,7 +357,7 @@ passes_collapse_debuginfo = passes_deprecated_annotation_has_no_effect = this `#[deprecated]` annotation has no effect .suggestion = remove the unnecessary deprecation attribute - + passes_unknown_external_lang_item = unknown external lang item: `{$lang_item}` @@ -389,3 +389,13 @@ passes_local_duplicate_lang_item = passes_invalid_attr_at_crate_level = `{$name}` attribute cannot be used at crate level .suggestion = perhaps you meant to use an outer attribute + +passes_duplicate_diagnostic_item = + duplicate diagnostic item found: `{$name}`. + +passes_duplicate_diagnostic_item_in_crate = + duplicate diagnostic item in crate `{$crate_name}`: `{$name}`. + +passes_diagnostic_item_first_defined = + the diagnostic item is first defined here + .note = the diagnostic item is first defined in crate `{$orig_crate_name}`. diff --git a/compiler/rustc_passes/src/diagnostic_items.rs b/compiler/rustc_passes/src/diagnostic_items.rs index e428d9293db17..c411a24716598 100644 --- a/compiler/rustc_passes/src/diagnostic_items.rs +++ b/compiler/rustc_passes/src/diagnostic_items.rs @@ -16,6 +16,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::def_id::{CrateNum, DefId, LocalDefId, LOCAL_CRATE}; use rustc_span::symbol::{sym, Symbol}; +use crate::errors::{DuplicateDiagnosticItem, DuplicateDiagnosticItemInCrate}; + fn observe_item<'tcx>( tcx: TyCtxt<'tcx>, diagnostic_items: &mut DiagnosticItems, @@ -33,25 +35,23 @@ fn collect_item(tcx: TyCtxt<'_>, items: &mut DiagnosticItems, name: Symbol, item items.id_to_name.insert(item_def_id, name); if let Some(original_def_id) = items.name_to_id.insert(name, item_def_id) { if original_def_id != item_def_id { - let mut err = match tcx.hir().span_if_local(item_def_id) { - Some(span) => tcx - .sess - .struct_span_err(span, &format!("duplicate diagnostic item found: `{name}`.")), - None => tcx.sess.struct_err(&format!( - "duplicate diagnostic item in crate `{}`: `{}`.", - tcx.crate_name(item_def_id.krate), - name - )), - }; - if let Some(span) = tcx.hir().span_if_local(original_def_id) { - err.span_note(span, "the diagnostic item is first defined here"); + let orig_span = tcx.hir().span_if_local(original_def_id); + let orig_crate_name = if orig_span.is_some() { + None } else { - err.note(&format!( - "the diagnostic item is first defined in crate `{}`.", - tcx.crate_name(original_def_id.krate) - )); - } - err.emit(); + Some(tcx.crate_name(original_def_id.krate)) + }; + match tcx.hir().span_if_local(item_def_id) { + Some(span) => tcx.sess.emit_err(DuplicateDiagnosticItem { span, name }), + None => tcx.sess.emit_err(DuplicateDiagnosticItemInCrate { + span: orig_span, + // FIXME: We should not provide `name` to `orig_crate_name`. How do you create a blank/empty symbol? + orig_crate_name: orig_crate_name.unwrap_or(name), + have_orig_crate_name: orig_crate_name.map(|_| ()), + crate_name: tcx.crate_name(item_def_id.krate), + name, + }), + }; } } } diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 26190af03587d..a94cac8c79542 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -755,3 +755,23 @@ impl IntoDiagnostic<'_> for InvalidAttrAtCrateLevel { diag } } + +#[derive(Diagnostic)] +#[diag(passes::duplicate_diagnostic_item)] +pub struct DuplicateDiagnosticItem { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes::duplicate_diagnostic_item_in_crate)] +pub struct DuplicateDiagnosticItemInCrate { + #[note(passes::diagnostic_item_first_defined)] + pub span: Option, + pub orig_crate_name: Symbol, + #[note] + pub have_orig_crate_name: Option<()>, + pub crate_name: Symbol, + pub name: Symbol, +} From 40d5f00e16230ce67c018bb05b8772f02634146c Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Fri, 23 Sep 2022 12:23:18 -0600 Subject: [PATCH 23/43] migrate layout_test.rs to translateable diagnostics --- .../locales/en-US/passes.ftl | 21 ++++++ compiler/rustc_passes/src/errors.rs | 57 +++++++++++++++ compiler/rustc_passes/src/layout_test.rs | 70 ++++++++++--------- 3 files changed, 115 insertions(+), 33 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 04fd0a3a6ac22..9493d95be5dc0 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -399,3 +399,24 @@ passes_duplicate_diagnostic_item_in_crate = passes_diagnostic_item_first_defined = the diagnostic item is first defined here .note = the diagnostic item is first defined in crate `{$orig_crate_name}`. + +passes_abi = + abi: {$abi} + +passes_align = + align: {$align} + +passes_size = + size: {$size} + +passes_homogeneous_aggregate = + homogeneous_aggregate: {$homogeneous_aggregate} + +passes_layout_of = + layout_of({$normalized_ty}) = {$ty_layout} + +passes_unrecognized_field = + unrecognized field name `{$name}` + +passes_layout = + layout error: {$layout_error} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index a94cac8c79542..e7a592d5a4748 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -775,3 +775,60 @@ pub struct DuplicateDiagnosticItemInCrate { pub crate_name: Symbol, pub name: Symbol, } + +#[derive(Diagnostic)] +#[diag(passes::abi)] +pub struct Abi { + #[primary_span] + pub span: Span, + pub abi: String, +} + +#[derive(Diagnostic)] +#[diag(passes::align)] +pub struct Align { + #[primary_span] + pub span: Span, + pub align: String, +} + +#[derive(Diagnostic)] +#[diag(passes::size)] +pub struct Size { + #[primary_span] + pub span: Span, + pub size: String, +} + +#[derive(Diagnostic)] +#[diag(passes::homogeneous_aggregate)] +pub struct HomogeneousAggregate { + #[primary_span] + pub span: Span, + pub homogeneous_aggregate: String, +} + +#[derive(Diagnostic)] +#[diag(passes::layout_of)] +pub struct LayoutOf { + #[primary_span] + pub span: Span, + pub normalized_ty: String, + pub ty_layout: String, +} + +#[derive(Diagnostic)] +#[diag(passes::unrecognized_field)] +pub struct UnrecognizedField { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes::layout)] +pub struct Layout { + #[primary_span] + pub span: Span, + pub layout_error: String, +} diff --git a/compiler/rustc_passes/src/layout_test.rs b/compiler/rustc_passes/src/layout_test.rs index 46c4a702fde95..7af1dda1ecbdb 100644 --- a/compiler/rustc_passes/src/layout_test.rs +++ b/compiler/rustc_passes/src/layout_test.rs @@ -7,6 +7,8 @@ use rustc_span::symbol::sym; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, TargetDataLayout}; +use crate::errors::{Abi, Align, HomogeneousAggregate, Layout, LayoutOf, Size, UnrecognizedField}; + pub fn test_layout(tcx: TyCtxt<'_>) { if tcx.features().rustc_attrs { // if the `rustc_attrs` feature is not enabled, don't bother testing layout @@ -35,62 +37,64 @@ fn dump_layout_of<'tcx>(tcx: TyCtxt<'tcx>, item_def_id: LocalDefId, attr: &Attri for meta_item in meta_items { match meta_item.name_or_empty() { sym::abi => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("abi: {:?}", ty_layout.abi), - ); + tcx.sess.emit_err(Abi { + span: tcx.def_span(item_def_id.to_def_id()), + abi: format!("{:?}", ty_layout.abi), + }); } sym::align => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("align: {:?}", ty_layout.align), - ); + tcx.sess.emit_err(Align { + span: tcx.def_span(item_def_id.to_def_id()), + align: format!("{:?}", ty_layout.align), + }); } sym::size => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("size: {:?}", ty_layout.size), - ); + tcx.sess.emit_err(Size { + span: tcx.def_span(item_def_id.to_def_id()), + size: format!("{:?}", ty_layout.size), + }); } sym::homogeneous_aggregate => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!( - "homogeneous_aggregate: {:?}", - ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }), + tcx.sess.emit_err(HomogeneousAggregate { + span: tcx.def_span(item_def_id.to_def_id()), + homogeneous_aggregate: format!( + "{:?}", + ty_layout.homogeneous_aggregate(&UnwrapLayoutCx { tcx, param_env }) ), - ); + }); } sym::debug => { - let normalized_ty = tcx.normalize_erasing_regions( - param_env.with_reveal_all_normalized(tcx), - ty, - ); - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("layout_of({:?}) = {:#?}", normalized_ty, *ty_layout), + let normalized_ty = format!( + "{:?}", + tcx.normalize_erasing_regions( + param_env.with_reveal_all_normalized(tcx), + ty, + ) ); + let ty_layout = format!("{:#?}", *ty_layout); + tcx.sess.emit_err(LayoutOf { + span: tcx.def_span(item_def_id.to_def_id()), + normalized_ty, + ty_layout, + }); } name => { - tcx.sess.span_err( - meta_item.span(), - &format!("unrecognized field name `{}`", name), - ); + tcx.sess.emit_err(UnrecognizedField { span: meta_item.span(), name }); } } } } Err(layout_error) => { - tcx.sess.span_err( - tcx.def_span(item_def_id.to_def_id()), - &format!("layout error: {:?}", layout_error), - ); + tcx.sess.emit_err(Layout { + span: tcx.def_span(item_def_id.to_def_id()), + layout_error: format!("{:?}", layout_error), + }); } } } From c457abee2e913ebb6f46329c15c6b43fbcb8c703 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sat, 24 Sep 2022 12:21:58 -0600 Subject: [PATCH 24/43] migrate lib_features.rs to translateable diagnostics --- .../locales/en-US/passes.ftl | 6 ++++ compiler/rustc_passes/src/errors.rs | 20 +++++++++++ compiler/rustc_passes/src/lib_features.rs | 34 ++++++++----------- 3 files changed, 40 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 9493d95be5dc0..b2c54aaccfe35 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -420,3 +420,9 @@ passes_unrecognized_field = passes_layout = layout error: {$layout_error} + +passes_feature_stable_twice = + feature `{$feature}` is declared stable since {$since}, but was previously declared stable since {$prev_since} + +passes_feature_previously_declared = + feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared} diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index e7a592d5a4748..7c3a575242f32 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -832,3 +832,23 @@ pub struct Layout { pub span: Span, pub layout_error: String, } + +#[derive(Diagnostic)] +#[diag(passes::feature_stable_twice, code = "E0711")] +pub struct FeatureStableTwice { + #[primary_span] + pub span: Span, + pub feature: Symbol, + pub since: Symbol, + pub prev_since: Symbol, +} + +#[derive(Diagnostic)] +#[diag(passes::feature_previously_declared, code = "E0711")] +pub struct FeaturePreviouslyDeclared<'a, 'b> { + #[primary_span] + pub span: Span, + pub feature: Symbol, + pub declared: &'a str, + pub prev_declared: &'b str, +} diff --git a/compiler/rustc_passes/src/lib_features.rs b/compiler/rustc_passes/src/lib_features.rs index 04173c792a979..b5843c0ae488b 100644 --- a/compiler/rustc_passes/src/lib_features.rs +++ b/compiler/rustc_passes/src/lib_features.rs @@ -6,7 +6,6 @@ use rustc_ast::{Attribute, MetaItemKind}; use rustc_attr::{rust_version_symbol, VERSION_PLACEHOLDER}; -use rustc_errors::struct_span_err; use rustc_hir::intravisit::Visitor; use rustc_middle::hir::nested_filter; use rustc_middle::middle::lib_features::LibFeatures; @@ -15,6 +14,8 @@ use rustc_middle::ty::TyCtxt; use rustc_span::symbol::Symbol; use rustc_span::{sym, Span}; +use crate::errors::{FeaturePreviouslyDeclared, FeatureStableTwice}; + fn new_lib_features() -> LibFeatures { LibFeatures { stable: Default::default(), unstable: Default::default() } } @@ -92,14 +93,12 @@ impl<'tcx> LibFeatureCollector<'tcx> { (Some(since), _, false) => { if let Some((prev_since, _)) = self.lib_features.stable.get(&feature) { if *prev_since != since { - self.span_feature_error( + self.tcx.sess.emit_err(FeatureStableTwice { span, - &format!( - "feature `{}` is declared stable since {}, \ - but was previously declared stable since {}", - feature, since, prev_since, - ), - ); + feature, + since, + prev_since: *prev_since, + }); return; } } @@ -110,22 +109,17 @@ impl<'tcx> LibFeatureCollector<'tcx> { self.lib_features.unstable.insert(feature, span); } (Some(_), _, true) | (None, true, _) => { - self.span_feature_error( + let declared = if since.is_some() { "stable" } else { "unstable" }; + let prev_declared = if since.is_none() { "stable" } else { "unstable" }; + self.tcx.sess.emit_err(FeaturePreviouslyDeclared { span, - &format!( - "feature `{}` is declared {}, but was previously declared {}", - feature, - if since.is_some() { "stable" } else { "unstable" }, - if since.is_none() { "stable" } else { "unstable" }, - ), - ); + feature, + declared, + prev_declared, + }); } } } - - fn span_feature_error(&self, span: Span, msg: &str) { - struct_span_err!(self.tcx.sess, span, E0711, "{}", &msg).emit(); - } } impl<'tcx> Visitor<'tcx> for LibFeatureCollector<'tcx> { From 572f3414b782311a8ec4143c50bbe3b006594898 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sat, 24 Sep 2022 12:49:29 -0600 Subject: [PATCH 25/43] migrate check_const.rs to translateable diagnostics --- .../locales/en-US/passes.ftl | 7 ++++ compiler/rustc_passes/src/check_const.rs | 33 ++++++++++++++++--- compiler/rustc_passes/src/errors.rs | 18 ++++++++++ 3 files changed, 54 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index b2c54aaccfe35..550096469bb0b 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -426,3 +426,10 @@ passes_feature_stable_twice = passes_feature_previously_declared = feature `{$feature}` is declared {$declared}, but was previously declared {$prev_declared} + +passes_expr_not_allowed_in_context = + {$expr} is not allowed in a `{$context}` + +passes_const_impl_const_trait = + const `impl`s must be for traits marked with `#[const_trait]` + .note = this trait must be annotated with `#[const_trait]` diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index e502b9b54e302..0a509598ec51d 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -8,7 +8,6 @@ //! through, but errors for structured control flow in a `const` should be emitted here. use rustc_attr as attr; -use rustc_errors::struct_span_err; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_hir::intravisit::{self, Visitor}; @@ -18,6 +17,8 @@ use rustc_middle::ty::TyCtxt; use rustc_session::parse::feature_err; use rustc_span::{sym, Span, Symbol}; +use crate::errors::{ConstImplConstTrait, ExprNotAllowedInContext}; + /// An expression that is not *always* legal in a const context. #[derive(Clone, Copy)] enum NonConstExpr { @@ -133,18 +134,22 @@ impl<'tcx> CheckConstVisitor<'tcx> { let const_kind = const_kind.expect("`const_check_violated` may only be called inside a const context"); - let msg = format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name()); - let required_gates = required_gates.unwrap_or(&[]); let missing_gates: Vec<_> = required_gates.iter().copied().filter(|&g| !features.enabled(g)).collect(); match missing_gates.as_slice() { [] => { - struct_span_err!(tcx.sess, span, E0744, "{}", msg).emit(); + tcx.sess.emit_err(ExprNotAllowedInContext { + span, + expr: expr.name(), + context: const_kind.keyword_name(), + }); } [missing_primary, ref missing_secondary @ ..] => { + let msg = + format!("{} is not allowed in a `{}`", expr.name(), const_kind.keyword_name()); let mut err = feature_err(&tcx.sess.parse_sess, *missing_primary, span, &msg); // If multiple feature gates would be required to enable this expression, include @@ -191,6 +196,26 @@ impl<'tcx> Visitor<'tcx> for CheckConstVisitor<'tcx> { self.tcx.hir() } + fn visit_item(&mut self, item: &'tcx hir::Item<'tcx>) { + let tcx = self.tcx; + if let hir::ItemKind::Impl(hir::Impl { + constness: hir::Constness::Const, + of_trait: Some(trait_ref), + .. + }) = item.kind + && let Some(def_id) = trait_ref.trait_def_id() + { + let source_map = tcx.sess.source_map(); + if !tcx.has_attr(def_id, sym::const_trait) { + tcx.sess.emit_err(ConstImplConstTrait { + span: source_map.guess_head_span(item.span), + def_span: source_map.guess_head_span(tcx.def_span(def_id)), + }); + } + } + intravisit::walk_item(self, item); + } + fn visit_anon_const(&mut self, anon: &'tcx hir::AnonConst) { let kind = Some(hir::ConstContext::Const); self.recurse_into(kind, None, |this| intravisit::walk_anon_const(this, anon)); diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index 7c3a575242f32..fe169c566f635 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -852,3 +852,21 @@ pub struct FeaturePreviouslyDeclared<'a, 'b> { pub declared: &'a str, pub prev_declared: &'b str, } + +#[derive(Diagnostic)] +#[diag(passes::expr_not_allowed_in_context, code = "E0744")] +pub struct ExprNotAllowedInContext<'a> { + #[primary_span] + pub span: Span, + pub expr: String, + pub context: &'a str, +} + +#[derive(Diagnostic)] +#[diag(passes::const_impl_const_trait)] +pub struct ConstImplConstTrait { + #[primary_span] + pub span: Span, + #[note] + pub def_span: Span, +} From 69766e4f167f4097e1f8975bd866c1f782fa26d5 Mon Sep 17 00:00:00 2001 From: Nathan Stocks Date: Sun, 25 Sep 2022 22:52:19 -0600 Subject: [PATCH 26/43] migrate loops.rs to translateable diagnostics --- .../locales/en-US/passes.ftl | 34 ++++ compiler/rustc_passes/src/errors.rs | 121 ++++++++++++- compiler/rustc_passes/src/loops.rs | 161 +++++------------- 3 files changed, 198 insertions(+), 118 deletions(-) diff --git a/compiler/rustc_error_messages/locales/en-US/passes.ftl b/compiler/rustc_error_messages/locales/en-US/passes.ftl index 550096469bb0b..3dc4204f986a4 100644 --- a/compiler/rustc_error_messages/locales/en-US/passes.ftl +++ b/compiler/rustc_error_messages/locales/en-US/passes.ftl @@ -433,3 +433,37 @@ passes_expr_not_allowed_in_context = passes_const_impl_const_trait = const `impl`s must be for traits marked with `#[const_trait]` .note = this trait must be annotated with `#[const_trait]` + +passes_break_non_loop = + `break` with value from a `{$kind}` loop + .label = can only break with a value inside `loop` or breakable block + .label2 = you can't `break` with a value in a `{$kind}` loop + .suggestion = use `break` on its own without a value inside this `{$kind}` loop + .break_expr_suggestion = alternatively, you might have meant to use the available loop label + +passes_continue_labeled_block = + `continue` pointing to a labeled block + .label = labeled blocks cannot be `continue`'d + .block_label = labeled block the `continue` points to + +passes_break_inside_closure = + `{$name}` inside of a closure + .label = cannot `{$name}` inside of a closure + .closure_label = enclosing closure + +passes_break_inside_async_block = + `{$name}` inside of an `async` block + .label = cannot `{$name}` inside of an `async` block + .async_block_label = enclosing `async` block + +passes_outside_loop = + `{$name}` outside of a loop + .label = cannot `{$name}` outside of a loop + +passes_unlabeled_in_labeled_block = + unlabeled `{$cf_type}` inside of a labeled block + .label = `{$cf_type}` statements that would diverge to or through a labeled block need to bear a label + +passes_unlabeled_cf_in_while_condition = + `break` or `continue` with no label in the condition of a `while` loop + .label = unlabeled `{$cf_type}` in the condition of a `while` loop diff --git a/compiler/rustc_passes/src/errors.rs b/compiler/rustc_passes/src/errors.rs index fe169c566f635..fcbcc298bd5b7 100644 --- a/compiler/rustc_passes/src/errors.rs +++ b/compiler/rustc_passes/src/errors.rs @@ -1,7 +1,8 @@ use std::{io::Error, path::Path}; -use rustc_errors::{Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; -use rustc_hir::Target; +use rustc_ast::Label; +use rustc_errors::{error_code, Applicability, ErrorGuaranteed, IntoDiagnostic, MultiSpan}; +use rustc_hir::{self as hir, ExprKind, Target}; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; use rustc_span::{Span, Symbol}; @@ -870,3 +871,119 @@ pub struct ConstImplConstTrait { #[note] pub def_span: Span, } + +pub struct BreakNonLoop<'a> { + pub span: Span, + pub head: Option, + pub kind: &'a str, + pub suggestion: String, + pub loop_label: Option