From 956fd10660e836ac4602527f7297aa68b24eca17 Mon Sep 17 00:00:00 2001 From: Marcus Calhoun-Lopez Date: Sun, 6 Jun 2021 12:49:42 -0700 Subject: [PATCH 01/12] Cross compiling rustc_llvm on Darwin requires zlib. --- compiler/rustc_llvm/build.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/rustc_llvm/build.rs b/compiler/rustc_llvm/build.rs index 452d1b19a18a8..964b7cace9cd4 100644 --- a/compiler/rustc_llvm/build.rs +++ b/compiler/rustc_llvm/build.rs @@ -182,7 +182,7 @@ fn main() { } else if target.contains("windows-gnu") { println!("cargo:rustc-link-lib=shell32"); println!("cargo:rustc-link-lib=uuid"); - } else if target.contains("netbsd") || target.contains("haiku") { + } else if target.contains("netbsd") || target.contains("haiku") || target.contains("darwin") { println!("cargo:rustc-link-lib=z"); } cmd.args(&components); From 886dea2bcdad68cadc13ea84e42df0c94179f79a Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 22 Jul 2021 14:28:02 -0500 Subject: [PATCH 02/12] Make `SEMICOLON_IN_EXPRESSIONS_FROM_MACROS` warn by default --- compiler/rustc_lint_defs/src/builtin.rs | 2 +- library/std/src/macros.rs | 2 +- src/test/ui/hygiene/auxiliary/intercrate.rs | 2 +- src/test/ui/hygiene/hygienic-label-1.rs | 2 +- src/test/ui/hygiene/hygienic-label-1.stderr | 4 ++-- src/test/ui/hygiene/hygienic-label-3.rs | 2 +- src/test/ui/hygiene/hygienic-label-3.stderr | 4 ++-- ...low-semicolon-in-expressions-from-macros.rs | 15 --------------- ...arn-semicolon-in-expressions-from-macros.rs | 16 ++++++++++++++++ ...semicolon-in-expressions-from-macros.stderr | 16 ++++++++++++++++ src/test/ui/macros/macro-context.rs | 2 ++ src/test/ui/macros/macro-context.stderr | 16 +++++++++++++++- .../macros/macro-in-expression-context.fixed | 8 ++++++++ .../ui/macros/macro-in-expression-context.rs | 8 ++++++++ .../macros/macro-in-expression-context.stderr | 18 ++++++++++++++++-- .../ui/proc-macro/nested-nonterminal-tokens.rs | 2 +- 16 files changed, 91 insertions(+), 28 deletions(-) delete mode 100644 src/test/ui/lint/semicolon-in-expressions-from-macros/allow-semicolon-in-expressions-from-macros.rs create mode 100644 src/test/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.rs create mode 100644 src/test/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr diff --git a/compiler/rustc_lint_defs/src/builtin.rs b/compiler/rustc_lint_defs/src/builtin.rs index 5b1cd0bcb3ffe..7195c41eae92e 100644 --- a/compiler/rustc_lint_defs/src/builtin.rs +++ b/compiler/rustc_lint_defs/src/builtin.rs @@ -2799,7 +2799,7 @@ declare_lint! { /// [issue #79813]: https://github.com/rust-lang/rust/issues/79813 /// [future-incompatible]: ../index.md#future-incompatible-lints pub SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, - Allow, + Warn, "trailing semicolon in macro body used as expression", @future_incompatible = FutureIncompatibleInfo { reference: "issue #79813 ", diff --git a/library/std/src/macros.rs b/library/std/src/macros.rs index 7afe52a3fd693..676695795badc 100644 --- a/library/std/src/macros.rs +++ b/library/std/src/macros.rs @@ -290,7 +290,7 @@ macro_rules! dbg { // `$val` expression could be a block (`{ .. }`), in which case the `eprintln!` // will be malformed. () => { - $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!()); + $crate::eprintln!("[{}:{}]", $crate::file!(), $crate::line!()) }; ($val:expr $(,)?) => { // Use of `match` here is intentional because it affects the lifetimes diff --git a/src/test/ui/hygiene/auxiliary/intercrate.rs b/src/test/ui/hygiene/auxiliary/intercrate.rs index 10d399ba54e71..0685358851edd 100644 --- a/src/test/ui/hygiene/auxiliary/intercrate.rs +++ b/src/test/ui/hygiene/auxiliary/intercrate.rs @@ -5,7 +5,7 @@ pub mod foo { mod bar { fn f() -> u32 { 1 } pub macro m() { - f(); + f() } } } diff --git a/src/test/ui/hygiene/hygienic-label-1.rs b/src/test/ui/hygiene/hygienic-label-1.rs index 66361eec21a52..a06d9255ab5b0 100644 --- a/src/test/ui/hygiene/hygienic-label-1.rs +++ b/src/test/ui/hygiene/hygienic-label-1.rs @@ -3,5 +3,5 @@ macro_rules! foo { } pub fn main() { - 'x: loop { foo!() } + 'x: loop { foo!(); } } diff --git a/src/test/ui/hygiene/hygienic-label-1.stderr b/src/test/ui/hygiene/hygienic-label-1.stderr index 97a7240b9069b..c1ed861836c1c 100644 --- a/src/test/ui/hygiene/hygienic-label-1.stderr +++ b/src/test/ui/hygiene/hygienic-label-1.stderr @@ -4,8 +4,8 @@ error[E0426]: use of undeclared label `'x` LL | () => { break 'x; } | ^^ undeclared label `'x` ... -LL | 'x: loop { foo!() } - | ------ in this macro invocation +LL | 'x: loop { foo!(); } + | ------- in this macro invocation | = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/hygiene/hygienic-label-3.rs b/src/test/ui/hygiene/hygienic-label-3.rs index a81eb84225970..ab0559e1b6a83 100644 --- a/src/test/ui/hygiene/hygienic-label-3.rs +++ b/src/test/ui/hygiene/hygienic-label-3.rs @@ -4,6 +4,6 @@ macro_rules! foo { pub fn main() { 'x: for _ in 0..1 { - foo!() + foo!(); }; } diff --git a/src/test/ui/hygiene/hygienic-label-3.stderr b/src/test/ui/hygiene/hygienic-label-3.stderr index 52840049f825a..29d1b67e09f9b 100644 --- a/src/test/ui/hygiene/hygienic-label-3.stderr +++ b/src/test/ui/hygiene/hygienic-label-3.stderr @@ -4,8 +4,8 @@ error[E0426]: use of undeclared label `'x` LL | () => { break 'x; } | ^^ undeclared label `'x` ... -LL | foo!() - | ------ in this macro invocation +LL | foo!(); + | ------- in this macro invocation | = note: this error originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/allow-semicolon-in-expressions-from-macros.rs b/src/test/ui/lint/semicolon-in-expressions-from-macros/allow-semicolon-in-expressions-from-macros.rs deleted file mode 100644 index 6f9e6ec0a57ff..0000000000000 --- a/src/test/ui/lint/semicolon-in-expressions-from-macros/allow-semicolon-in-expressions-from-macros.rs +++ /dev/null @@ -1,15 +0,0 @@ -// check-pass -// Ensure that trailing semicolons are allowed by default - -macro_rules! foo { - () => { - true; - } -} - -fn main() { - let val = match true { - true => false, - _ => foo!() - }; -} diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.rs b/src/test/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.rs new file mode 100644 index 0000000000000..2c63311e65978 --- /dev/null +++ b/src/test/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.rs @@ -0,0 +1,16 @@ +// check-pass +// Ensure that trailing semicolons cause warnings by default + +macro_rules! foo { + () => { + true; //~ WARN trailing semicolon in macro + //~| WARN this was previously + } +} + +fn main() { + let _val = match true { + true => false, + _ => foo!() + }; +} diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr b/src/test/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr new file mode 100644 index 0000000000000..d770a8c8f36e6 --- /dev/null +++ b/src/test/ui/lint/semicolon-in-expressions-from-macros/warn-semicolon-in-expressions-from-macros.stderr @@ -0,0 +1,16 @@ +warning: trailing semicolon in macro used in expression position + --> $DIR/warn-semicolon-in-expressions-from-macros.rs:6:13 + | +LL | true; + | ^ +... +LL | _ => foo!() + | ------ in this macro invocation + | + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +warning: 1 warning emitted + diff --git a/src/test/ui/macros/macro-context.rs b/src/test/ui/macros/macro-context.rs index 13e179578ad01..d09fdf118e6f4 100644 --- a/src/test/ui/macros/macro-context.rs +++ b/src/test/ui/macros/macro-context.rs @@ -6,6 +6,8 @@ macro_rules! m { //~| ERROR macro expansion ignores token `;` //~| ERROR cannot find type `i` in this scope //~| ERROR cannot find value `i` in this scope + //~| WARN trailing semicolon in macro + //~| WARN this was previously } fn main() { diff --git a/src/test/ui/macros/macro-context.stderr b/src/test/ui/macros/macro-context.stderr index 5ed73b7fb93a3..3b8a6f1749158 100644 --- a/src/test/ui/macros/macro-context.stderr +++ b/src/test/ui/macros/macro-context.stderr @@ -64,7 +64,21 @@ LL | let i = m!(); | = note: this error originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 6 previous errors +warning: trailing semicolon in macro used in expression position + --> $DIR/macro-context.rs:3:15 + | +LL | () => ( i ; typeof ); + | ^ +... +LL | let i = m!(); + | ---- in this macro invocation + | + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: this warning originates in the macro `m` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 6 previous errors; 1 warning emitted Some errors have detailed explanations: E0412, E0425. For more information about an error, try `rustc --explain E0412`. diff --git a/src/test/ui/macros/macro-in-expression-context.fixed b/src/test/ui/macros/macro-in-expression-context.fixed index df36db0f49e72..3fb4e0dbfa649 100644 --- a/src/test/ui/macros/macro-in-expression-context.fixed +++ b/src/test/ui/macros/macro-in-expression-context.fixed @@ -3,6 +3,10 @@ macro_rules! foo { () => { assert_eq!("A", "A"); + //~^ WARN trailing semicolon in macro + //~| WARN this was previously + //~| NOTE for more information + //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); } //~^^ ERROR macro expansion ignores token `assert_eq` and any following @@ -12,4 +16,8 @@ macro_rules! foo { fn main() { foo!(); //~^ NOTE caused by the macro expansion here + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion } diff --git a/src/test/ui/macros/macro-in-expression-context.rs b/src/test/ui/macros/macro-in-expression-context.rs index b3f5e568967e8..fc434071dcd28 100644 --- a/src/test/ui/macros/macro-in-expression-context.rs +++ b/src/test/ui/macros/macro-in-expression-context.rs @@ -3,6 +3,10 @@ macro_rules! foo { () => { assert_eq!("A", "A"); + //~^ WARN trailing semicolon in macro + //~| WARN this was previously + //~| NOTE for more information + //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); } //~^^ ERROR macro expansion ignores token `assert_eq` and any following @@ -12,4 +16,8 @@ macro_rules! foo { fn main() { foo!() //~^ NOTE caused by the macro expansion here + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion } diff --git a/src/test/ui/macros/macro-in-expression-context.stderr b/src/test/ui/macros/macro-in-expression-context.stderr index d27d6fbaef7a6..ddc1709a27093 100644 --- a/src/test/ui/macros/macro-in-expression-context.stderr +++ b/src/test/ui/macros/macro-in-expression-context.stderr @@ -1,5 +1,5 @@ error: macro expansion ignores token `assert_eq` and any following - --> $DIR/macro-in-expression-context.rs:6:9 + --> $DIR/macro-in-expression-context.rs:10:9 | LL | assert_eq!("B", "B"); | ^^^^^^^^^ @@ -11,5 +11,19 @@ LL | foo!() | = note: the usage of `foo!` is likely invalid in expression context -error: aborting due to previous error +warning: trailing semicolon in macro used in expression position + --> $DIR/macro-in-expression-context.rs:5:29 + | +LL | assert_eq!("A", "A"); + | ^ +... +LL | foo!() + | ------ in this macro invocation + | + = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default + = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! + = note: for more information, see issue #79813 + = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to previous error; 1 warning emitted diff --git a/src/test/ui/proc-macro/nested-nonterminal-tokens.rs b/src/test/ui/proc-macro/nested-nonterminal-tokens.rs index 2f5af10a40ac2..04d34e21cdc74 100644 --- a/src/test/ui/proc-macro/nested-nonterminal-tokens.rs +++ b/src/test/ui/proc-macro/nested-nonterminal-tokens.rs @@ -17,7 +17,7 @@ macro_rules! wrap { (first, $e:expr) => { wrap!(second, $e + 1) }; (second, $e:expr) => { wrap!(third, $e + 2) }; (third, $e:expr) => { - print_bang!($e + 3); + print_bang!($e + 3) }; } From cf167c9c9c0576472b67f5498a074bc697c9af23 Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Sat, 24 Jul 2021 17:44:57 -0500 Subject: [PATCH 03/12] Only emit lint for local macros --- compiler/rustc_expand/src/mbe/macro_rules.rs | 26 ++++++++++++++----- .../auxiliary/foreign-crate.rs | 4 +++ .../foreign-crate.rs | 9 +++++++ 3 files changed, 32 insertions(+), 7 deletions(-) create mode 100644 src/test/ui/lint/semicolon-in-expressions-from-macros/auxiliary/foreign-crate.rs create mode 100644 src/test/ui/lint/semicolon-in-expressions-from-macros/foreign-crate.rs diff --git a/compiler/rustc_expand/src/mbe/macro_rules.rs b/compiler/rustc_expand/src/mbe/macro_rules.rs index b97593b92b355..9aee86c9e57dd 100644 --- a/compiler/rustc_expand/src/mbe/macro_rules.rs +++ b/compiler/rustc_expand/src/mbe/macro_rules.rs @@ -45,6 +45,8 @@ crate struct ParserAnyMacro<'a> { lint_node_id: NodeId, is_trailing_mac: bool, arm_span: Span, + /// Whether or not this macro is defined in the current crate + is_local: bool, } crate fn annotate_err_with_kind( @@ -124,6 +126,7 @@ impl<'a> ParserAnyMacro<'a> { lint_node_id, arm_span, is_trailing_mac, + is_local, } = *self; let snapshot = &mut parser.clone(); let fragment = match parse_ast_fragment(parser, kind) { @@ -138,13 +141,15 @@ impl<'a> ParserAnyMacro<'a> { // `macro_rules! m { () => { panic!(); } }` isn't parsed by `.parse_expr()`, // but `m!()` is allowed in expression positions (cf. issue #34706). if kind == AstFragmentKind::Expr && parser.token == token::Semi { - parser.sess.buffer_lint_with_diagnostic( - SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, - parser.token.span, - lint_node_id, - "trailing semicolon in macro used in expression position", - BuiltinLintDiagnostics::TrailingMacro(is_trailing_mac, macro_ident), - ); + if is_local { + parser.sess.buffer_lint_with_diagnostic( + SEMICOLON_IN_EXPRESSIONS_FROM_MACROS, + parser.token.span, + lint_node_id, + "trailing semicolon in macro used in expression position", + BuiltinLintDiagnostics::TrailingMacro(is_trailing_mac, macro_ident), + ); + } parser.bump(); } @@ -162,6 +167,7 @@ struct MacroRulesMacroExpander { lhses: Vec, rhses: Vec, valid: bool, + is_local: bool, } impl TTMacroExpander for MacroRulesMacroExpander { @@ -183,6 +189,7 @@ impl TTMacroExpander for MacroRulesMacroExpander { input, &self.lhses, &self.rhses, + self.is_local, ) } } @@ -210,6 +217,7 @@ fn generic_extension<'cx>( arg: TokenStream, lhses: &[mbe::TokenTree], rhses: &[mbe::TokenTree], + is_local: bool, ) -> Box { let sess = &cx.sess.parse_sess; @@ -311,6 +319,7 @@ fn generic_extension<'cx>( lint_node_id: cx.current_expansion.lint_node_id, is_trailing_mac: cx.current_expansion.is_trailing_mac, arm_span, + is_local, }); } Failure(token, msg) => match best_failure { @@ -544,6 +553,9 @@ pub fn compile_declarative_macro( lhses, rhses, valid, + // Macros defined in the current crate have a real node id, + // whereas macros from an external crate have a dummy id. + is_local: def.id != DUMMY_NODE_ID, })) } diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/auxiliary/foreign-crate.rs b/src/test/ui/lint/semicolon-in-expressions-from-macros/auxiliary/foreign-crate.rs new file mode 100644 index 0000000000000..781391cc574a9 --- /dev/null +++ b/src/test/ui/lint/semicolon-in-expressions-from-macros/auxiliary/foreign-crate.rs @@ -0,0 +1,4 @@ +#[macro_export] +macro_rules! my_macro { + () => { true; } +} diff --git a/src/test/ui/lint/semicolon-in-expressions-from-macros/foreign-crate.rs b/src/test/ui/lint/semicolon-in-expressions-from-macros/foreign-crate.rs new file mode 100644 index 0000000000000..374506366f802 --- /dev/null +++ b/src/test/ui/lint/semicolon-in-expressions-from-macros/foreign-crate.rs @@ -0,0 +1,9 @@ +// aux-build:foreign-crate.rs +// check-pass + +extern crate foreign_crate; + +// Test that we do not lint for a macro in a foreign crate +fn main() { + let _ = foreign_crate::my_macro!(); +} From 6954f9d4f21837e145b4aa629262a62b5f21fa8f Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Tue, 27 Jul 2021 17:50:18 -0500 Subject: [PATCH 04/12] Update stderr --- src/test/ui/macros/macro-in-expression-context.fixed | 4 ++++ src/test/ui/macros/macro-in-expression-context.rs | 4 ++++ src/test/ui/macros/macro-in-expression-context.stderr | 4 +++- 3 files changed, 11 insertions(+), 1 deletion(-) diff --git a/src/test/ui/macros/macro-in-expression-context.fixed b/src/test/ui/macros/macro-in-expression-context.fixed index 3fb4e0dbfa649..f22caf2793fd5 100644 --- a/src/test/ui/macros/macro-in-expression-context.fixed +++ b/src/test/ui/macros/macro-in-expression-context.fixed @@ -5,6 +5,8 @@ macro_rules! foo { assert_eq!("A", "A"); //~^ WARN trailing semicolon in macro //~| WARN this was previously + //~| NOTE macro invocations at the end of a block + //~| NOTE to ignore the value produced by the macro //~| NOTE for more information //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); @@ -20,4 +22,6 @@ fn main() { //~| NOTE in this expansion //~| NOTE in this expansion //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion } diff --git a/src/test/ui/macros/macro-in-expression-context.rs b/src/test/ui/macros/macro-in-expression-context.rs index fc434071dcd28..1a056e582ff47 100644 --- a/src/test/ui/macros/macro-in-expression-context.rs +++ b/src/test/ui/macros/macro-in-expression-context.rs @@ -5,6 +5,8 @@ macro_rules! foo { assert_eq!("A", "A"); //~^ WARN trailing semicolon in macro //~| WARN this was previously + //~| NOTE macro invocations at the end of a block + //~| NOTE to ignore the value produced by the macro //~| NOTE for more information //~| NOTE `#[warn(semicolon_in_expressions_from_macros)]` on by default assert_eq!("B", "B"); @@ -20,4 +22,6 @@ fn main() { //~| NOTE in this expansion //~| NOTE in this expansion //~| NOTE in this expansion + //~| NOTE in this expansion + //~| NOTE in this expansion } diff --git a/src/test/ui/macros/macro-in-expression-context.stderr b/src/test/ui/macros/macro-in-expression-context.stderr index ddc1709a27093..1840babd61dc2 100644 --- a/src/test/ui/macros/macro-in-expression-context.stderr +++ b/src/test/ui/macros/macro-in-expression-context.stderr @@ -1,5 +1,5 @@ error: macro expansion ignores token `assert_eq` and any following - --> $DIR/macro-in-expression-context.rs:10:9 + --> $DIR/macro-in-expression-context.rs:12:9 | LL | assert_eq!("B", "B"); | ^^^^^^^^^ @@ -23,6 +23,8 @@ LL | foo!() = note: `#[warn(semicolon_in_expressions_from_macros)]` on by default = warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release! = note: for more information, see issue #79813 + = note: macro invocations at the end of a block are treated as expressions + = note: to ignore the value produced by the macro, add a semicolon after the invocation of `foo` = note: this warning originates in the macro `foo` (in Nightly builds, run with -Z macro-backtrace for more info) error: aborting due to previous error; 1 warning emitted From e70ce57f306c730c7a949942671cd525e281f2ec Mon Sep 17 00:00:00 2001 From: Aaron Hill Date: Thu, 29 Jul 2021 09:52:35 -0500 Subject: [PATCH 05/12] Remove unnecessary trailing semicolons from clippy tests --- src/tools/clippy/tests/ui/needless_borrow_pat.rs | 2 +- src/tools/clippy/tests/ui/ref_binding_to_reference.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/src/tools/clippy/tests/ui/needless_borrow_pat.rs b/src/tools/clippy/tests/ui/needless_borrow_pat.rs index f0926220755a2..7a8137778b446 100644 --- a/src/tools/clippy/tests/ui/needless_borrow_pat.rs +++ b/src/tools/clippy/tests/ui/needless_borrow_pat.rs @@ -7,7 +7,7 @@ fn f1(_: &str) {} macro_rules! m1 { ($e:expr) => { - f1($e); + f1($e) }; } macro_rules! m3 { diff --git a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs index c7235e1c22105..cd6db8ddc8864 100644 --- a/src/tools/clippy/tests/ui/ref_binding_to_reference.rs +++ b/src/tools/clippy/tests/ui/ref_binding_to_reference.rs @@ -7,7 +7,7 @@ fn f1(_: &str) {} macro_rules! m2 { ($e:expr) => { - f1(*$e); + f1(*$e) }; } macro_rules! m3 { From 5b5391e283e591520235d7aafd6f1f0aa3b6ce22 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 30 Jul 2021 04:49:08 +0900 Subject: [PATCH 06/12] Add some TAIT-related regression tests --- src/test/ui/type-alias-impl-trait/issue-74280.rs | 13 +++++++++++++ .../ui/type-alias-impl-trait/issue-74280.stderr | 14 ++++++++++++++ src/test/ui/type-alias-impl-trait/issue-77179.rs | 14 ++++++++++++++ .../ui/type-alias-impl-trait/issue-77179.stderr | 12 ++++++++++++ 4 files changed, 53 insertions(+) create mode 100644 src/test/ui/type-alias-impl-trait/issue-74280.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-74280.stderr create mode 100644 src/test/ui/type-alias-impl-trait/issue-77179.rs create mode 100644 src/test/ui/type-alias-impl-trait/issue-77179.stderr diff --git a/src/test/ui/type-alias-impl-trait/issue-74280.rs b/src/test/ui/type-alias-impl-trait/issue-74280.rs new file mode 100644 index 0000000000000..d5b90a49b0521 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-74280.rs @@ -0,0 +1,13 @@ +// Regression test for #74280. + +#![feature(type_alias_impl_trait)] + +type Test = impl Copy; + +fn test() -> Test { + let y = || -> Test { () }; + //~^ ERROR: concrete type differs from previous defining opaque type use + 7 +} + +fn main() {} diff --git a/src/test/ui/type-alias-impl-trait/issue-74280.stderr b/src/test/ui/type-alias-impl-trait/issue-74280.stderr new file mode 100644 index 0000000000000..79c7df788f46c --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-74280.stderr @@ -0,0 +1,14 @@ +error: concrete type differs from previous defining opaque type use + --> $DIR/issue-74280.rs:8:13 + | +LL | let y = || -> Test { () }; + | ^^^^^^^^^^^^^^^^^ expected `i32`, got `()` + | +note: previous use here + --> $DIR/issue-74280.rs:7:1 + | +LL | fn test() -> Test { + | ^^^^^^^^^^^^^^^^^ + +error: aborting due to previous error + diff --git a/src/test/ui/type-alias-impl-trait/issue-77179.rs b/src/test/ui/type-alias-impl-trait/issue-77179.rs new file mode 100644 index 0000000000000..31c45a2093a04 --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-77179.rs @@ -0,0 +1,14 @@ +// Regression test for #77179. + +#![feature(type_alias_impl_trait)] + +type Pointer = impl std::ops::Deref; + +fn test() -> Pointer<_> { + //~^ ERROR: the type placeholder `_` is not allowed within types + Box::new(1) +} + +fn main() { + test(); +} diff --git a/src/test/ui/type-alias-impl-trait/issue-77179.stderr b/src/test/ui/type-alias-impl-trait/issue-77179.stderr new file mode 100644 index 0000000000000..593aeeacb83aa --- /dev/null +++ b/src/test/ui/type-alias-impl-trait/issue-77179.stderr @@ -0,0 +1,12 @@ +error[E0121]: the type placeholder `_` is not allowed within types on item signatures for return types + --> $DIR/issue-77179.rs:7:22 + | +LL | fn test() -> Pointer<_> { + | --------^- + | | | + | | not allowed in type signatures + | help: replace with the correct return type: `Box` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0121`. From 5cc7702bde47716c66734c488432850fab1a83dd Mon Sep 17 00:00:00 2001 From: Lukas Kalbertodt Date: Fri, 30 Jul 2021 00:08:48 +0200 Subject: [PATCH 07/12] Add docs about performance and `Iterator::map` to `[T; N]::map` --- library/core/src/array/mod.rs | 22 ++++++++++++++++++++++ 1 file changed, 22 insertions(+) diff --git a/library/core/src/array/mod.rs b/library/core/src/array/mod.rs index 78b799cd70976..3bc9f71375cb8 100644 --- a/library/core/src/array/mod.rs +++ b/library/core/src/array/mod.rs @@ -293,6 +293,28 @@ impl [T; N] { /// Returns an array of the same size as `self`, with function `f` applied to each element /// in order. /// + /// If you don't necessarily need a new fixed-size array, consider using + /// [`Iterator::map`] instead. + /// + /// + /// # Note on performance and stack usage + /// + /// Unfortunately, usages of this method are currently not always optimized + /// as well as they could be. This mainly concerns large arrays, as mapping + /// over small arrays seem to be optimized just fine. Also note that in + /// debug mode (i.e. without any optimizations), this method can use a lot + /// of stack space (a few times the size of the array or more). + /// + /// Therefore, in performance-critical code, try to avoid using this method + /// on large arrays or check the emitted code. Also try to avoid chained + /// maps (e.g. `arr.map(...).map(...)`). + /// + /// In many cases, you can instead use [`Iterator::map`] by calling `.iter()` + /// or `.into_iter()` on your array. `[T; N]::map` is only necessary if you + /// really need a new array of the same size as the result. Rust's lazy + /// iterators tend to get optimized very well. + /// + /// /// # Examples /// /// ``` From c2a365d3d4b5c067adfe8462a749e0c40746617a Mon Sep 17 00:00:00 2001 From: Wilfred Hughes Date: Fri, 30 Jul 2021 00:58:48 -0700 Subject: [PATCH 08/12] Fix missing word in comment --- src/doc/rustdoc/src/command-line-arguments.md | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/doc/rustdoc/src/command-line-arguments.md b/src/doc/rustdoc/src/command-line-arguments.md index c8af369a9695e..d694862266254 100644 --- a/src/doc/rustdoc/src/command-line-arguments.md +++ b/src/doc/rustdoc/src/command-line-arguments.md @@ -94,7 +94,7 @@ $ rustdoc src/lib.rs --document-private-items By default, `rustdoc` only documents items that are publicly reachable. ```rust -pub fn public() {} // this item is public and will documented +pub fn public() {} // this item is public and will be documented mod private { // this item is private and will not be documented pub fn unreachable() {} // this item is public, but unreachable, so it will not be documented } From 1bbe6188d255a2466fba7220db80536bf7d12672 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 28 Jul 2021 14:24:23 +0200 Subject: [PATCH 09/12] Add missing examples for NonNull --- library/core/src/ptr/non_null.rs | 88 ++++++++++++++++++++++++++++++++ 1 file changed, 88 insertions(+) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 3ab40f1faa1d6..032df7f5a80ad 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -71,6 +71,16 @@ impl NonNull { /// a `T`, which means this must not be used as a "not yet initialized" /// sentinel value. Types that lazily allocate must track initialization by /// some other means. + /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let ptr = NonNull::::dangling(); + /// // Important: don't try to access the value of `ptr` without + /// // initializing it first! The pointer is not null but isn't valid either! + /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_dangling", since = "1.36.0")] #[inline] @@ -155,6 +165,18 @@ impl NonNull { /// # Safety /// /// `ptr` must be non-null. + /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let ptr = unsafe { NonNull::new_unchecked(&mut x as *mut _) }; + /// + /// // NEVER DO THAT!!! + /// let ptr = unsafe { NonNull::::new_unchecked(std::ptr::null_mut()) }; + /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_new_unchecked", since = "1.25.0")] #[inline] @@ -164,6 +186,19 @@ impl NonNull { } /// Creates a new `NonNull` if `ptr` is non-null. + /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let ptr = NonNull::::new(&mut x as *mut _).expect("ptr is null!"); + /// + /// if let Some(ptr) = NonNull::::new(std::ptr::null_mut()) { + /// unreachable!(); + /// } + /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[inline] pub fn new(ptr: *mut T) -> Option { @@ -205,6 +240,22 @@ impl NonNull { } /// Acquires the underlying `*mut` pointer. + /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let ptr = NonNull::new(&mut x).expect("ptr is null!"); + /// + /// let x_value = unsafe { *ptr.as_ptr() }; + /// assert_eq!(x_value, 0); + /// + /// unsafe { *ptr.as_ptr() += 2; } + /// let x_value = unsafe { *ptr.as_ptr() }; + /// assert_eq!(x_value, 2); + /// ``` #[stable(feature = "nonnull", since = "1.25.0")] #[rustc_const_stable(feature = "const_nonnull_as_ptr", since = "1.32.0")] #[inline] @@ -239,6 +290,18 @@ impl NonNull { /// (The part about being initialized is not yet fully decided, but until /// it is, the only safe approach is to ensure that they are indeed initialized.) /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let ptr = NonNull::new(&mut x as *mut _).expect("ptr is null!"); + /// + /// let ref_x = unsafe { ptr.as_ref() }; + /// println!("{}", ref_x); + /// ``` + /// /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] #[inline] @@ -274,6 +337,19 @@ impl NonNull { /// This applies even if the result of this method is unused! /// (The part about being initialized is not yet fully decided, but until /// it is, the only safe approach is to ensure that they are indeed initialized.) + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let mut ptr = NonNull::new(&mut x).expect("null pointer"); + /// + /// let x_ref = unsafe { ptr.as_mut() }; + /// assert_eq!(*x_ref, 0); + /// *x_ref += 2; + /// assert_eq!(*x_ref, 2); + /// ``` /// /// [the module documentation]: crate::ptr#safety #[stable(feature = "nonnull", since = "1.25.0")] @@ -285,6 +361,18 @@ impl NonNull { } /// Casts to a pointer of another type. + /// + /// # Examples + /// + /// ``` + /// use std::ptr::NonNull; + /// + /// let mut x = 0u32; + /// let ptr = NonNull::new(&mut x as *mut _).expect("null pointer"); + /// + /// let casted_ptr = ptr.cast::(); + /// let raw_ptr: *mut i8 = casted_ptr.as_ptr(); + /// ``` #[stable(feature = "nonnull_cast", since = "1.27.0")] #[rustc_const_stable(feature = "const_nonnull_cast", since = "1.36.0")] #[inline] From 5d59b4412e71298e6e44b55afbfaa9dd86aee590 Mon Sep 17 00:00:00 2001 From: Anton Golov Date: Fri, 30 Jul 2021 16:09:33 +0200 Subject: [PATCH 10/12] Add warning when whitespace is not skipped after an escaped newline. --- compiler/rustc_ast/src/util/literal.rs | 24 ++++++++++--- compiler/rustc_lexer/src/unescape.rs | 34 ++++++++++++++++--- compiler/rustc_lexer/src/unescape/tests.rs | 19 +++++++++++ .../src/lexer/unescape_error_reporting.rs | 6 ++++ 4 files changed, 75 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_ast/src/util/literal.rs b/compiler/rustc_ast/src/util/literal.rs index 2124f1efb990c..9c6ad47427d21 100644 --- a/compiler/rustc_ast/src/util/literal.rs +++ b/compiler/rustc_ast/src/util/literal.rs @@ -63,7 +63,11 @@ impl LitKind { unescape_literal(&s, Mode::Str, &mut |_, unescaped_char| { match unescaped_char { Ok(c) => buf.push(c), - Err(_) => error = Err(LitError::LexerError), + Err(err) => { + if err.is_fatal() { + error = Err(LitError::LexerError); + } + } } }); error?; @@ -83,7 +87,11 @@ impl LitKind { unescape_literal(&s, Mode::RawStr, &mut |_, unescaped_char| { match unescaped_char { Ok(c) => buf.push(c), - Err(_) => error = Err(LitError::LexerError), + Err(err) => { + if err.is_fatal() { + error = Err(LitError::LexerError); + } + } } }); error?; @@ -100,7 +108,11 @@ impl LitKind { unescape_byte_literal(&s, Mode::ByteStr, &mut |_, unescaped_byte| { match unescaped_byte { Ok(c) => buf.push(c), - Err(_) => error = Err(LitError::LexerError), + Err(err) => { + if err.is_fatal() { + error = Err(LitError::LexerError); + } + } } }); error?; @@ -114,7 +126,11 @@ impl LitKind { unescape_byte_literal(&s, Mode::RawByteStr, &mut |_, unescaped_byte| { match unescaped_byte { Ok(c) => buf.push(c), - Err(_) => error = Err(LitError::LexerError), + Err(err) => { + if err.is_fatal() { + error = Err(LitError::LexerError); + } + } } }); error?; diff --git a/compiler/rustc_lexer/src/unescape.rs b/compiler/rustc_lexer/src/unescape.rs index b4dd0fc2449ec..9a96c03cd3c80 100644 --- a/compiler/rustc_lexer/src/unescape.rs +++ b/compiler/rustc_lexer/src/unescape.rs @@ -7,7 +7,7 @@ use std::str::Chars; #[cfg(test)] mod tests; -/// Errors that can occur during string unescaping. +/// Errors and warnings that can occur during string unescaping. #[derive(Debug, PartialEq, Eq)] pub enum EscapeError { /// Expected 1 char, but 0 were found. @@ -56,6 +56,20 @@ pub enum EscapeError { NonAsciiCharInByte, /// Non-ascii character in byte string literal. NonAsciiCharInByteString, + + /// After a line ending with '\', the next line contains whitespace + /// characters that are not skipped. + UnskippedWhitespaceWarning, +} + +impl EscapeError { + /// Returns true for actual errors, as opposed to warnings. + pub fn is_fatal(&self) -> bool { + match self { + EscapeError::UnskippedWhitespaceWarning => false, + _ => true, + } + } } /// Takes a contents of a literal (without quotes) and produces a @@ -283,7 +297,7 @@ where // if unescaped '\' character is followed by '\n'. // For details see [Rust language reference] // (https://doc.rust-lang.org/reference/tokens.html#string-literals). - skip_ascii_whitespace(&mut chars); + skip_ascii_whitespace(&mut chars, start, callback); continue; } _ => scan_escape(first_char, &mut chars, mode), @@ -297,13 +311,25 @@ where callback(start..end, unescaped_char); } - fn skip_ascii_whitespace(chars: &mut Chars<'_>) { + fn skip_ascii_whitespace(chars: &mut Chars<'_>, start: usize, callback: &mut F) + where + F: FnMut(Range, Result), + { let str = chars.as_str(); let first_non_space = str .bytes() .position(|b| b != b' ' && b != b'\t' && b != b'\n' && b != b'\r') .unwrap_or(str.len()); - *chars = str[first_non_space..].chars() + let tail = &str[first_non_space..]; + if let Some(c) = tail.chars().nth(0) { + // For error reporting, we would like the span to contain the character that was not + // skipped. The +1 is necessary to account for the leading \ that started the escape. + let end = start + first_non_space + c.len_utf8() + 1; + if c.is_whitespace() { + callback(start..end, Err(EscapeError::UnskippedWhitespaceWarning)); + } + } + *chars = tail.chars(); } } diff --git a/compiler/rustc_lexer/src/unescape/tests.rs b/compiler/rustc_lexer/src/unescape/tests.rs index f2b751a78f27f..1f4dbb20f4e98 100644 --- a/compiler/rustc_lexer/src/unescape/tests.rs +++ b/compiler/rustc_lexer/src/unescape/tests.rs @@ -98,6 +98,25 @@ fn test_unescape_char_good() { check(r"\u{1F63b}", '😻'); } +#[test] +fn test_unescape_str_warn() { + fn check(literal: &str, expected: &[(Range, Result)]) { + let mut unescaped = Vec::with_capacity(literal.len()); + unescape_literal(literal, Mode::Str, &mut |range, res| unescaped.push((range, res))); + assert_eq!(unescaped, expected); + } + + check( + "\\\n \u{a0} x", + &[ + (0..5, Err(EscapeError::UnskippedWhitespaceWarning)), + (3..5, Ok('\u{a0}')), + (5..6, Ok(' ')), + (6..7, Ok('x')), + ], + ); +} + #[test] fn test_unescape_str_good() { fn check(literal_text: &str, expected: &str) { diff --git a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs index a580f0c55d0e3..1c5be61130b61 100644 --- a/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs +++ b/compiler/rustc_parse/src/lexer/unescape_error_reporting.rs @@ -253,6 +253,12 @@ pub(crate) fn emit_unescape_error( let msg = "invalid trailing slash in literal"; handler.struct_span_err(span, msg).span_label(span, msg).emit(); } + EscapeError::UnskippedWhitespaceWarning => { + let (c, char_span) = last_char(); + let msg = + format!("non-ASCII whitespace symbol '{}' is not skipped", c.escape_unicode()); + handler.struct_span_warn(span, &msg).span_label(char_span, &msg).emit(); + } } } From 578fcbdb3c4cb893f5bd1d884788d60e2a2b6786 Mon Sep 17 00:00:00 2001 From: Ryan Levick Date: Wed, 28 Jul 2021 18:34:19 +0200 Subject: [PATCH 11/12] Fix error with suggestion for how to disambiguate associated function when struct is generic --- .../src/check/method/prelude2021.rs | 21 +++++++++-- .../future-prelude-collision-generic.fixed | 37 +++++++++++++++++++ .../future-prelude-collision-generic.rs | 37 +++++++++++++++++++ .../future-prelude-collision-generic.stderr | 34 +++++++++++++++++ src/test/ui/{ => rust-2021}/prelude2021.rs | 0 5 files changed, 126 insertions(+), 3 deletions(-) create mode 100644 src/test/ui/rust-2021/future-prelude-collision-generic.fixed create mode 100644 src/test/ui/rust-2021/future-prelude-collision-generic.rs create mode 100644 src/test/ui/rust-2021/future-prelude-collision-generic.stderr rename src/test/ui/{ => rust-2021}/prelude2021.rs (100%) diff --git a/compiler/rustc_typeck/src/check/method/prelude2021.rs b/compiler/rustc_typeck/src/check/method/prelude2021.rs index f13e23914f7ab..6eb8af98640eb 100644 --- a/compiler/rustc_typeck/src/check/method/prelude2021.rs +++ b/compiler/rustc_typeck/src/check/method/prelude2021.rs @@ -5,7 +5,7 @@ use rustc_ast::Mutability; use rustc_errors::Applicability; use rustc_hir as hir; use rustc_middle::ty::subst::InternalSubsts; -use rustc_middle::ty::{Ref, Ty}; +use rustc_middle::ty::{Adt, Ref, Ty}; use rustc_session::lint::builtin::RUST_2021_PRELUDE_COLLISIONS; use rustc_span::symbol::kw::Underscore; use rustc_span::symbol::{sym, Ident}; @@ -255,16 +255,31 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { method_name.name )); - let self_ty = self + let self_ty_name = self .sess() .source_map() .span_to_snippet(self_ty_span) .unwrap_or_else(|_| self_ty.to_string()); + let self_ty_generics_count = match self_ty.kind() { + // Get the number of generics the self type has (if an Adt) unless we can determine that + // the user has written the self type with generics already which we (naively) do by looking + // for a "<" in `self_ty_name`. + Adt(def, _) if !self_ty_name.contains("<") => self.tcx.generics_of(def.did).count(), + _ => 0, + }; + let self_ty_generics = if self_ty_generics_count > 0 { + format!("<{}>", vec!["_"; self_ty_generics_count].join(", ")) + } else { + String::new() + }; lint.span_suggestion( span, "disambiguate the associated function", - format!("<{} as {}>::{}", self_ty, trait_name, method_name.name,), + format!( + "<{}{} as {}>::{}", + self_ty_name, self_ty_generics, trait_name, method_name.name, + ), Applicability::MachineApplicable, ); diff --git a/src/test/ui/rust-2021/future-prelude-collision-generic.fixed b/src/test/ui/rust-2021/future-prelude-collision-generic.fixed new file mode 100644 index 0000000000000..f0d8cb944cf84 --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-generic.fixed @@ -0,0 +1,37 @@ +// test for https://github.com/rust-lang/rust/issues/86940 +// run-rustfix +// edition:2018 +// check-pass +#![warn(rust_2021_prelude_collisions)] +#![allow(dead_code)] +#![allow(unused_imports)] + +struct Generic(T, U); + +trait MyFromIter { + fn from_iter(_: i32) -> Self; +} + +impl MyFromIter for Generic { + fn from_iter(x: i32) -> Self { + Self(x, x) + } +} + +impl std::iter::FromIterator for Generic { + fn from_iter>(_: T) -> Self { + todo!() + } +} + +fn main() { + as MyFromIter>::from_iter(1); + //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 + //~| this is accepted in the current edition (Rust 2018) + as MyFromIter>::from_iter(1); + //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 + //~| this is accepted in the current edition (Rust 2018) + as MyFromIter>::from_iter(1); + //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 + //~| this is accepted in the current edition (Rust 2018) +} diff --git a/src/test/ui/rust-2021/future-prelude-collision-generic.rs b/src/test/ui/rust-2021/future-prelude-collision-generic.rs new file mode 100644 index 0000000000000..1984053705984 --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-generic.rs @@ -0,0 +1,37 @@ +// test for https://github.com/rust-lang/rust/issues/86940 +// run-rustfix +// edition:2018 +// check-pass +#![warn(rust_2021_prelude_collisions)] +#![allow(dead_code)] +#![allow(unused_imports)] + +struct Generic(T, U); + +trait MyFromIter { + fn from_iter(_: i32) -> Self; +} + +impl MyFromIter for Generic { + fn from_iter(x: i32) -> Self { + Self(x, x) + } +} + +impl std::iter::FromIterator for Generic { + fn from_iter>(_: T) -> Self { + todo!() + } +} + +fn main() { + Generic::from_iter(1); + //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 + //~| this is accepted in the current edition (Rust 2018) + Generic::::from_iter(1); + //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 + //~| this is accepted in the current edition (Rust 2018) + Generic::<_, _>::from_iter(1); + //~^ WARNING trait-associated function `from_iter` will become ambiguous in Rust 2021 + //~| this is accepted in the current edition (Rust 2018) +} diff --git a/src/test/ui/rust-2021/future-prelude-collision-generic.stderr b/src/test/ui/rust-2021/future-prelude-collision-generic.stderr new file mode 100644 index 0000000000000..2c6a63df42f2c --- /dev/null +++ b/src/test/ui/rust-2021/future-prelude-collision-generic.stderr @@ -0,0 +1,34 @@ +warning: trait-associated function `from_iter` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-generic.rs:28:5 + | +LL | Generic::from_iter(1); + | ^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: ` as MyFromIter>::from_iter` + | +note: the lint level is defined here + --> $DIR/future-prelude-collision-generic.rs:5:9 + | +LL | #![warn(rust_2021_prelude_collisions)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^ + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + = note: for more information, see issue #85684 + +warning: trait-associated function `from_iter` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-generic.rs:31:5 + | +LL | Generic::::from_iter(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: ` as MyFromIter>::from_iter` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + = note: for more information, see issue #85684 + +warning: trait-associated function `from_iter` will become ambiguous in Rust 2021 + --> $DIR/future-prelude-collision-generic.rs:34:5 + | +LL | Generic::<_, _>::from_iter(1); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ help: disambiguate the associated function: ` as MyFromIter>::from_iter` + | + = warning: this is accepted in the current edition (Rust 2018) but is a hard error in Rust 2021! + = note: for more information, see issue #85684 + +warning: 3 warnings emitted + diff --git a/src/test/ui/prelude2021.rs b/src/test/ui/rust-2021/prelude2021.rs similarity index 100% rename from src/test/ui/prelude2021.rs rename to src/test/ui/rust-2021/prelude2021.rs From 17b2f92e44b65caa5e057c51560336311caf2fb4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Esteban=20K=C3=BCber?= Date: Wed, 28 Jul 2021 10:08:39 -0700 Subject: [PATCH 12/12] Tweak borrowing suggestion in `for` loop --- .../borrow_check/diagnostics/move_errors.rs | 69 +++++++++++-------- src/test/ui/suggestions/for-i-in-vec.fixed | 3 + src/test/ui/suggestions/for-i-in-vec.rs | 3 + src/test/ui/suggestions/for-i-in-vec.stderr | 25 +++++-- .../ui/suggestions/option-content-move.stderr | 20 +++--- 5 files changed, 76 insertions(+), 44 deletions(-) diff --git a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs index 3f87d9c7ac948..2be23159bf563 100644 --- a/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs +++ b/compiler/rustc_mir/src/borrow_check/diagnostics/move_errors.rs @@ -2,7 +2,8 @@ use rustc_errors::{Applicability, DiagnosticBuilder}; use rustc_middle::mir::*; use rustc_middle::ty; use rustc_span::source_map::DesugaringKind; -use rustc_span::{sym, Span}; +use rustc_span::{sym, Span, DUMMY_SP}; +use rustc_trait_selection::traits::type_known_to_meet_bound_modulo_regions; use crate::borrow_check::diagnostics::UseSpans; use crate::borrow_check::prefixes::PrefixSet; @@ -384,36 +385,44 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } } }; - if let Ok(snippet) = self.infcx.tcx.sess.source_map().span_to_snippet(span) { - let def_id = match *move_place.ty(self.body, self.infcx.tcx).ty.kind() { - ty::Adt(self_def, _) => self_def.did, - ty::Foreign(def_id) - | ty::FnDef(def_id, _) - | ty::Closure(def_id, _) - | ty::Generator(def_id, ..) - | ty::Opaque(def_id, _) => def_id, - _ => return err, + let ty = move_place.ty(self.body, self.infcx.tcx).ty; + let def_id = match *ty.kind() { + ty::Adt(self_def, _) => self_def.did, + ty::Foreign(def_id) + | ty::FnDef(def_id, _) + | ty::Closure(def_id, _) + | ty::Generator(def_id, ..) + | ty::Opaque(def_id, _) => def_id, + _ => return err, + }; + let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id); + let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id); + if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) { + err.span_suggestion_verbose( + span.shrink_to_hi(), + &format!( + "consider borrowing the `{}`'s content", + if is_option { "Option" } else { "Result" } + ), + ".as_ref()".to_string(), + Applicability::MaybeIncorrect, + ); + } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) { + let suggest = match self.infcx.tcx.get_diagnostic_item(sym::IntoIterator) { + Some(def_id) => type_known_to_meet_bound_modulo_regions( + &self.infcx, + self.param_env, + self.infcx.tcx.mk_imm_ref(self.infcx.tcx.lifetimes.re_erased, ty), + def_id, + DUMMY_SP, + ), + _ => false, }; - let is_option = self.infcx.tcx.is_diagnostic_item(sym::option_type, def_id); - let is_result = self.infcx.tcx.is_diagnostic_item(sym::result_type, def_id); - if (is_option || is_result) && use_spans.map_or(true, |v| !v.for_closure()) { - err.span_suggestion( - span, - &format!( - "consider borrowing the `{}`'s content", - if is_option { "Option" } else { "Result" } - ), - format!("{}.as_ref()", snippet), - Applicability::MaybeIncorrect, - ); - } else if matches!(span.desugaring_kind(), Some(DesugaringKind::ForLoop(_))) - && self.infcx.tcx.is_diagnostic_item(sym::vec_type, def_id) - { - // FIXME: suggest for anything that implements `IntoIterator`. - err.span_suggestion( - span, - "consider iterating over a slice of the `Vec<_>`'s content", - format!("&{}", snippet), + if suggest { + err.span_suggestion_verbose( + span.shrink_to_lo(), + &format!("consider iterating over a slice of the `{}`'s content", ty), + "&".to_string(), Applicability::MaybeIncorrect, ); } diff --git a/src/test/ui/suggestions/for-i-in-vec.fixed b/src/test/ui/suggestions/for-i-in-vec.fixed index ec7358bd08ad2..223ddf0f0ad2a 100644 --- a/src/test/ui/suggestions/for-i-in-vec.fixed +++ b/src/test/ui/suggestions/for-i-in-vec.fixed @@ -3,12 +3,15 @@ struct Foo { v: Vec, + h: std::collections::HashMap, } impl Foo { fn bar(&self) { for _ in &self.v { //~ ERROR cannot move out of `self.v` which is behind a shared reference } + for _ in &self.h { //~ ERROR cannot move out of `self.h` which is behind a shared reference + } } } diff --git a/src/test/ui/suggestions/for-i-in-vec.rs b/src/test/ui/suggestions/for-i-in-vec.rs index 304fe8cc81f1a..7942698cc8eff 100644 --- a/src/test/ui/suggestions/for-i-in-vec.rs +++ b/src/test/ui/suggestions/for-i-in-vec.rs @@ -3,12 +3,15 @@ struct Foo { v: Vec, + h: std::collections::HashMap, } impl Foo { fn bar(&self) { for _ in self.v { //~ ERROR cannot move out of `self.v` which is behind a shared reference } + for _ in self.h { //~ ERROR cannot move out of `self.h` which is behind a shared reference + } } } diff --git a/src/test/ui/suggestions/for-i-in-vec.stderr b/src/test/ui/suggestions/for-i-in-vec.stderr index 48f3f423ac638..011fdf34c28b5 100644 --- a/src/test/ui/suggestions/for-i-in-vec.stderr +++ b/src/test/ui/suggestions/for-i-in-vec.stderr @@ -1,12 +1,25 @@ error[E0507]: cannot move out of `self.v` which is behind a shared reference - --> $DIR/for-i-in-vec.rs:10:18 + --> $DIR/for-i-in-vec.rs:11:18 | LL | for _ in self.v { - | ^^^^^^ - | | - | move occurs because `self.v` has type `Vec`, which does not implement the `Copy` trait - | help: consider iterating over a slice of the `Vec<_>`'s content: `&self.v` + | ^^^^^^ move occurs because `self.v` has type `Vec`, which does not implement the `Copy` trait + | +help: consider iterating over a slice of the `Vec`'s content + | +LL | for _ in &self.v { + | ^ + +error[E0507]: cannot move out of `self.h` which is behind a shared reference + --> $DIR/for-i-in-vec.rs:13:18 + | +LL | for _ in self.h { + | ^^^^^^ move occurs because `self.h` has type `HashMap`, which does not implement the `Copy` trait + | +help: consider iterating over a slice of the `HashMap`'s content + | +LL | for _ in &self.h { + | ^ -error: aborting due to previous error +error: aborting due to 2 previous errors For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/suggestions/option-content-move.stderr b/src/test/ui/suggestions/option-content-move.stderr index c00a0f1700bb4..9476653009155 100644 --- a/src/test/ui/suggestions/option-content-move.stderr +++ b/src/test/ui/suggestions/option-content-move.stderr @@ -2,19 +2,23 @@ error[E0507]: cannot move out of `selection.1` which is behind a shared referenc --> $DIR/option-content-move.rs:11:20 | LL | if selection.1.unwrap().contains(selection.0) { - | ^^^^^^^^^^^ - | | - | move occurs because `selection.1` has type `Option`, which does not implement the `Copy` trait - | help: consider borrowing the `Option`'s content: `selection.1.as_ref()` + | ^^^^^^^^^^^ move occurs because `selection.1` has type `Option`, which does not implement the `Copy` trait + | +help: consider borrowing the `Option`'s content + | +LL | if selection.1.as_ref().unwrap().contains(selection.0) { + | ^^^^^^^^^ error[E0507]: cannot move out of `selection.1` which is behind a shared reference --> $DIR/option-content-move.rs:29:20 | LL | if selection.1.unwrap().contains(selection.0) { - | ^^^^^^^^^^^ - | | - | move occurs because `selection.1` has type `Result`, which does not implement the `Copy` trait - | help: consider borrowing the `Result`'s content: `selection.1.as_ref()` + | ^^^^^^^^^^^ move occurs because `selection.1` has type `Result`, which does not implement the `Copy` trait + | +help: consider borrowing the `Result`'s content + | +LL | if selection.1.as_ref().unwrap().contains(selection.0) { + | ^^^^^^^^^ error: aborting due to 2 previous errors