From ab83d501a404bede933df8f33e280a7534cc71bf Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Sun, 12 Sep 2021 23:07:23 +0200 Subject: [PATCH 01/14] Do not issue E0071 if a type error has already been reported --- .../src/error_codes/E0071.md | 18 ++++++------ .../rustc_typeck/src/check/fn_ctxt/checks.rs | 28 +++++++++++++------ src/test/ui/typeck/issue-88844.rs | 14 ++++++++++ src/test/ui/typeck/issue-88844.stderr | 12 ++++++++ 4 files changed, 54 insertions(+), 18 deletions(-) create mode 100644 src/test/ui/typeck/issue-88844.rs create mode 100644 src/test/ui/typeck/issue-88844.stderr diff --git a/compiler/rustc_error_codes/src/error_codes/E0071.md b/compiler/rustc_error_codes/src/error_codes/E0071.md index bc2c03a0220..a6d6d19762b 100644 --- a/compiler/rustc_error_codes/src/error_codes/E0071.md +++ b/compiler/rustc_error_codes/src/error_codes/E0071.md @@ -15,13 +15,13 @@ form of initializer was used. For example, the code above can be fixed to: ``` -enum Foo { - FirstValue(i32) -} - -fn main() { - let u = Foo::FirstValue(0i32); - - let t = 4; -} +type U32 = u32; +let t: U32 = 4; +``` + +or: + +``` +struct U32 { value: u32 } +let t = U32 { value: 4 }; ``` diff --git a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs index 9efb52a08b7..e74e79fd1bf 100644 --- a/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs +++ b/compiler/rustc_typeck/src/check/fn_ctxt/checks.rs @@ -494,15 +494,25 @@ pub fn check_struct_path( Some((variant, ty)) } else { - struct_span_err!( - self.tcx.sess, - path_span, - E0071, - "expected struct, variant or union type, found {}", - ty.sort_string(self.tcx) - ) - .span_label(path_span, "not a struct") - .emit(); + match ty.kind() { + ty::Error(_) => { + // E0071 might be caused by a spelling error, which will have + // already caused an error message and probably a suggestion + // elsewhere. Refrain from emitting more unhelpful errors here + // (issue #88844). + } + _ => { + struct_span_err!( + self.tcx.sess, + path_span, + E0071, + "expected struct, variant or union type, found {}", + ty.sort_string(self.tcx) + ) + .span_label(path_span, "not a struct") + .emit(); + } + } None } } diff --git a/src/test/ui/typeck/issue-88844.rs b/src/test/ui/typeck/issue-88844.rs new file mode 100644 index 00000000000..116c75aabdb --- /dev/null +++ b/src/test/ui/typeck/issue-88844.rs @@ -0,0 +1,14 @@ +// Regression test for #88844. + +struct Struct { value: i32 } +//~^ NOTE: similarly named struct `Struct` defined here + +impl Stuct { +//~^ ERROR: cannot find type `Stuct` in this scope [E0412] +//~| HELP: a struct with a similar name exists + fn new() -> Self { + Self { value: 42 } + } +} + +fn main() {} diff --git a/src/test/ui/typeck/issue-88844.stderr b/src/test/ui/typeck/issue-88844.stderr new file mode 100644 index 00000000000..90bba90be34 --- /dev/null +++ b/src/test/ui/typeck/issue-88844.stderr @@ -0,0 +1,12 @@ +error[E0412]: cannot find type `Stuct` in this scope + --> $DIR/issue-88844.rs:6:6 + | +LL | struct Struct { value: i32 } + | ------------- similarly named struct `Struct` defined here +... +LL | impl Stuct { + | ^^^^^ help: a struct with a similar name exists: `Struct` + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0412`. From 2a2bfd1e59e9f84d2f68c0587bd7d7c93a237a46 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Wed, 15 Sep 2021 00:11:18 +0200 Subject: [PATCH 02/14] Fix handling of `hir::GenericArg::Infer` in `wrong_number_of_generic_args.rs` --- .../wrong_number_of_generic_args.rs | 14 +++++--------- 1 file changed, 5 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs index bccc19774e0..7e69ad21d03 100644 --- a/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs +++ b/compiler/rustc_typeck/src/structured_errors/wrong_number_of_generic_args.rs @@ -136,10 +136,7 @@ fn num_provided_lifetime_args(&self) -> usize { AngleBrackets::Missing => 0, // Only lifetime arguments can be implied AngleBrackets::Implied => self.gen_args.args.len(), - AngleBrackets::Available => self.gen_args.args.iter().fold(0, |acc, arg| match arg { - hir::GenericArg::Lifetime(_) => acc + 1, - _ => acc, - }), + AngleBrackets::Available => self.gen_args.num_lifetime_params(), } } @@ -148,10 +145,7 @@ fn num_provided_type_or_const_args(&self) -> usize { AngleBrackets::Missing => 0, // Only lifetime arguments can be implied AngleBrackets::Implied => 0, - AngleBrackets::Available => self.gen_args.args.iter().fold(0, |acc, arg| match arg { - hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => acc + 1, - _ => acc, - }), + AngleBrackets::Available => self.gen_args.num_generic_params(), } } @@ -651,7 +645,9 @@ fn suggest_removing_args_or_generics(&self, err: &mut DiagnosticBuilder<'_>) { let mut found_redundant = false; for arg in self.gen_args.args { match arg { - hir::GenericArg::Type(_) | hir::GenericArg::Const(_) => { + hir::GenericArg::Type(_) + | hir::GenericArg::Const(_) + | hir::GenericArg::Infer(_) => { gen_arg_spans.push(arg.span()); if gen_arg_spans.len() > self.num_expected_type_or_const_args() { found_redundant = true; From 21b7052eb87c397094484227eec75269061d8491 Mon Sep 17 00:00:00 2001 From: Fabian Wolff Date: Sun, 25 Jul 2021 20:05:41 +0200 Subject: [PATCH 03/14] Point to closure when emitting 'cannot move out' for captured variable --- .../src/diagnostics/move_errors.rs | 12 +- .../ui/borrowck/borrowck-in-static.stderr | 5 +- .../borrowck/borrowck-move-by-capture.stderr | 21 +- .../borrowck/issue-87456-point-to-closure.rs | 14 + .../issue-87456-point-to-closure.stderr | 22 + ...ove-upvar-from-non-once-ref-closure.stderr | 14 +- src/test/ui/issues/issue-4335.stderr | 5 +- ...-move-out-of-closure-env-issue-1965.stderr | 5 +- ...e-52663-span-decl-captured-variable.stderr | 5 +- ...borrowck-call-is-borrow-issue-12224.stderr | 14 +- .../dont-suggest-ref/move-into-closure.stderr | 554 ++++++++++++------ .../suggestions/option-content-move2.stderr | 27 +- .../unboxed-closure-illegal-move.stderr | 20 +- 13 files changed, 503 insertions(+), 215 deletions(-) create mode 100644 src/test/ui/borrowck/issue-87456-point-to-closure.rs create mode 100644 src/test/ui/borrowck/issue-87456-point-to-closure.stderr diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 3c114084586..b23ce281bef 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -336,15 +336,15 @@ fn report_cannot_move_from_borrowed_content( if def_id.as_local() == Some(self.mir_def_id()) && upvar_field.is_some() => { let closure_kind_ty = closure_substs.as_closure().kind_ty(); - let closure_kind = closure_kind_ty.to_opt_closure_kind(); - let capture_description = match closure_kind { - Some(ty::ClosureKind::Fn) => "captured variable in an `Fn` closure", - Some(ty::ClosureKind::FnMut) => "captured variable in an `FnMut` closure", + let closure_kind = match closure_kind_ty.to_opt_closure_kind() { + Some(kind @ (ty::ClosureKind::Fn | ty::ClosureKind::FnMut)) => kind, Some(ty::ClosureKind::FnOnce) => { bug!("closure kind does not match first argument type") } None => bug!("closure kind not inferred by borrowck"), }; + let capture_description = + format!("captured variable in an `{}` closure", closure_kind); let upvar = &self.upvars[upvar_field.unwrap().index()]; let upvar_hir_id = upvar.place.get_root_variable(); @@ -368,6 +368,10 @@ fn report_cannot_move_from_borrowed_content( let mut diag = self.cannot_move_out_of(span, &place_description); diag.span_label(upvar_span, "captured outer variable"); + diag.span_label( + self.body.span, + format!("captured by this `{}` closure", closure_kind), + ); diag } diff --git a/src/test/ui/borrowck/borrowck-in-static.stderr b/src/test/ui/borrowck/borrowck-in-static.stderr index f73c787346d..30e74c5ec95 100644 --- a/src/test/ui/borrowck/borrowck-in-static.stderr +++ b/src/test/ui/borrowck/borrowck-in-static.stderr @@ -4,7 +4,10 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | Box::new(|| x) - | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | ---^ + | | | + | | move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | captured by this `Fn` closure error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-by-capture.stderr b/src/test/ui/borrowck/borrowck-move-by-capture.stderr index 628f206e0a8..05489cf18e7 100644 --- a/src/test/ui/borrowck/borrowck-move-by-capture.stderr +++ b/src/test/ui/borrowck/borrowck-move-by-capture.stderr @@ -1,15 +1,18 @@ error[E0507]: cannot move out of `bar`, a captured variable in an `FnMut` closure --> $DIR/borrowck-move-by-capture.rs:9:29 | -LL | let bar: Box<_> = box 3; - | --- captured outer variable -LL | let _g = to_fn_mut(|| { -LL | let _h = to_fn_once(move || -> isize { *bar }); - | ^^^^^^^^^^^^^^^^ ---- - | | | - | | move occurs because `bar` has type `Box`, which does not implement the `Copy` trait - | | move occurs due to use in closure - | move out of `bar` occurs here +LL | let bar: Box<_> = box 3; + | --- captured outer variable +LL | let _g = to_fn_mut(|| { + | ________________________- +LL | | let _h = to_fn_once(move || -> isize { *bar }); + | | ^^^^^^^^^^^^^^^^ ---- + | | | | + | | | move occurs because `bar` has type `Box`, which does not implement the `Copy` trait + | | | move occurs due to use in closure + | | move out of `bar` occurs here +LL | | }); + | |_____- captured by this `FnMut` closure error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-87456-point-to-closure.rs b/src/test/ui/borrowck/issue-87456-point-to-closure.rs new file mode 100644 index 00000000000..9fc12ba7490 --- /dev/null +++ b/src/test/ui/borrowck/issue-87456-point-to-closure.rs @@ -0,0 +1,14 @@ +// Regression test for #87456. + +fn take_mut(_val: impl FnMut()) {} + +fn main() { + let val = String::new(); + //~^ NOTE: captured outer variable + take_mut(|| { + //~^ NOTE: captured by this `FnMut` closure + let _foo: String = val; + //~^ ERROR: cannot move out of `val`, a captured variable in an `FnMut` closure [E0507] + //~| NOTE: move occurs because + }) +} diff --git a/src/test/ui/borrowck/issue-87456-point-to-closure.stderr b/src/test/ui/borrowck/issue-87456-point-to-closure.stderr new file mode 100644 index 00000000000..fd38ad7bb0a --- /dev/null +++ b/src/test/ui/borrowck/issue-87456-point-to-closure.stderr @@ -0,0 +1,22 @@ +error[E0507]: cannot move out of `val`, a captured variable in an `FnMut` closure + --> $DIR/issue-87456-point-to-closure.rs:10:28 + | +LL | let val = String::new(); + | --- captured outer variable +LL | +LL | take_mut(|| { + | ______________- +LL | | +LL | | let _foo: String = val; + | | ^^^ + | | | + | | move occurs because `val` has type `String`, which does not implement the `Copy` trait + | | help: consider borrowing here: `&val` +LL | | +LL | | +LL | | }) + | |_____- captured by this `FnMut` closure + +error: aborting due to previous error + +For more information about this error, try `rustc --explain E0507`. diff --git a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr index dbba33f0183..1663ce81d6c 100644 --- a/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr +++ b/src/test/ui/borrowck/unboxed-closures-move-upvar-from-non-once-ref-closure.stderr @@ -1,11 +1,15 @@ error[E0507]: cannot move out of `y`, a captured variable in an `Fn` closure --> $DIR/unboxed-closures-move-upvar-from-non-once-ref-closure.rs:11:9 | -LL | let y = vec![format!("World")]; - | - captured outer variable -LL | call(|| { -LL | y.into_iter(); - | ^ move occurs because `y` has type `Vec`, which does not implement the `Copy` trait +LL | let y = vec![format!("World")]; + | - captured outer variable +LL | call(|| { + | __________- +LL | | y.into_iter(); + | | ^ move occurs because `y` has type `Vec`, which does not implement the `Copy` trait +LL | | +LL | | }); + | |_____- captured by this `Fn` closure error: aborting due to previous error diff --git a/src/test/ui/issues/issue-4335.stderr b/src/test/ui/issues/issue-4335.stderr index f187969ff4e..fa3b58e1279 100644 --- a/src/test/ui/issues/issue-4335.stderr +++ b/src/test/ui/issues/issue-4335.stderr @@ -4,7 +4,10 @@ error[E0507]: cannot move out of `*v`, as `v` is a captured variable in an `FnMu LL | fn f<'r, T>(v: &'r T) -> Box T + 'r> { | - captured outer variable LL | id(Box::new(|| *v)) - | ^^ move occurs because `*v` has type `T`, which does not implement the `Copy` trait + | ---^^ + | | | + | | move occurs because `*v` has type `T`, which does not implement the `Copy` trait + | captured by this `FnMut` closure error: aborting due to previous error diff --git a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr index 9427ba546a9..e12af2d4527 100644 --- a/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr +++ b/src/test/ui/moves/moves-based-on-type-move-out-of-closure-env-issue-1965.stderr @@ -4,7 +4,10 @@ error[E0507]: cannot move out of `i`, a captured variable in an `Fn` closure LL | let i = box 3; | - captured outer variable LL | let _f = to_fn(|| test(i)); - | ^ move occurs because `i` has type `Box`, which does not implement the `Copy` trait + | --------^- + | | | + | | move occurs because `i` has type `Box`, which does not implement the `Copy` trait + | captured by this `Fn` closure error: aborting due to previous error diff --git a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr index 67115a5ccdd..c9324f0422c 100644 --- a/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr +++ b/src/test/ui/nll/issue-52663-span-decl-captured-variable.stderr @@ -4,7 +4,10 @@ error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` LL | let x = (vec![22], vec![44]); | - captured outer variable LL | expect_fn(|| drop(x.0)); - | ^^^ move occurs because `x.0` has type `Vec`, which does not implement the `Copy` trait + | --------^^^- + | | | + | | move occurs because `x.0` has type `Vec`, which does not implement the `Copy` trait + | captured by this `Fn` closure error: aborting due to previous error diff --git a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr index ab1fa2a4d87..0f630abd148 100644 --- a/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr +++ b/src/test/ui/span/borrowck-call-is-borrow-issue-12224.stderr @@ -29,11 +29,17 @@ LL | f.f.call_mut(()) error[E0507]: cannot move out of `f`, a captured variable in an `FnMut` closure --> $DIR/borrowck-call-is-borrow-issue-12224.rs:57:13 | -LL | let mut f = move |g: Box, b: isize| { - | ----- captured outer variable +LL | let mut f = move |g: Box, b: isize| { + | ----- captured outer variable ... -LL | foo(f); - | ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6]`, which does not implement the `Copy` trait +LL | f(Box::new(|a| { + | ________________- +LL | | +LL | | foo(f); + | | ^ move occurs because `f` has type `[closure@$DIR/borrowck-call-is-borrow-issue-12224.rs:52:17: 54:6]`, which does not implement the `Copy` trait +LL | | +LL | | }), 3); + | |_____- captured by this `FnMut` closure error[E0505]: cannot move out of `f` because it is borrowed --> $DIR/borrowck-call-is-borrow-issue-12224.rs:55:16 diff --git a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr index c50cbcde855..fb1055c9c30 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr +++ b/src/test/ui/suggestions/dont-suggest-ref/move-into-closure.stderr @@ -1,281 +1,487 @@ error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:28:21 | -LL | let x = X(Y); - | - captured outer variable +LL | let x = X(Y); + | - captured outer variable ... -LL | let X(_t) = x; - | -- ^ help: consider borrowing here: `&x` - | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; + | | -- ^ help: consider borrowing here: `&x` + | | | + | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | | +LL | | +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:32:34 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | if let Either::One(_t) = e { } - | -- ^ help: consider borrowing here: `&e` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +LL | | +LL | | if let Either::One(_t) = e { } + | | -- ^ help: consider borrowing here: `&e` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:36:37 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | while let Either::One(_t) = e { } - | -- ^ help: consider borrowing here: `&e` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | while let Either::One(_t) = e { } + | | -- ^ help: consider borrowing here: `&e` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:40:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | match e { - | ^ help: consider borrowing here: `&e` -... -LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match e { + | | ^ help: consider borrowing here: `&e` +... | +LL | | Either::One(_t) + | | -- + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:47:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | match e { - | ^ help: consider borrowing here: `&e` -... -LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match e { + | | ^ help: consider borrowing here: `&e` +... | +LL | | Either::One(_t) => (), + | | -- + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:56:25 | -LL | let x = X(Y); - | - captured outer variable +LL | let x = X(Y); + | - captured outer variable ... -LL | let X(mut _t) = x; - | ------ ^ help: consider borrowing here: `&x` - | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | let X(mut _t) = x; + | | ------ ^ help: consider borrowing here: `&x` + | | | + | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:60:38 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | if let Either::One(mut _t) = em { } - | ------ ^^ help: consider borrowing here: `&em` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | if let Either::One(mut _t) = em { } + | | ------ ^^ help: consider borrowing here: `&em` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:64:41 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | while let Either::One(mut _t) = em { } - | ------ ^^ help: consider borrowing here: `&em` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | while let Either::One(mut _t) = em { } + | | ------ ^^ help: consider borrowing here: `&em` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:68:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | match em { - | ^^ help: consider borrowing here: `&em` -... -LL | Either::One(mut _t) - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match em { + | | ^^ help: consider borrowing here: `&em` +... | +LL | | Either::One(mut _t) + | | ------ + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `Fn` closure --> $DIR/move-into-closure.rs:75:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | match em { - | ^^ help: consider borrowing here: `&em` -... -LL | Either::One(mut _t) => (), - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fn(|| { + | ________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match em { + | | ^^ help: consider borrowing here: `&em` +... | +LL | | Either::One(mut _t) => (), + | | ------ + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `Fn` closure error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:95:21 | -LL | let x = X(Y); - | - captured outer variable +LL | let x = X(Y); + | - captured outer variable ... -LL | let X(_t) = x; - | -- ^ help: consider borrowing here: `&x` - | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; + | | -- ^ help: consider borrowing here: `&x` + | | | + | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | | +LL | | +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:99:34 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | if let Either::One(_t) = e { } - | -- ^ help: consider borrowing here: `&e` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +LL | | +LL | | if let Either::One(_t) = e { } + | | -- ^ help: consider borrowing here: `&e` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:103:37 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | while let Either::One(_t) = e { } - | -- ^ help: consider borrowing here: `&e` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | while let Either::One(_t) = e { } + | | -- ^ help: consider borrowing here: `&e` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:107:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | match e { - | ^ help: consider borrowing here: `&e` -... -LL | Either::One(_t) - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match e { + | | ^ help: consider borrowing here: `&e` +... | +LL | | Either::One(_t) + | | -- + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `e.0`, as `e` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:114:15 | -LL | let e = Either::One(X(Y)); - | - captured outer variable +LL | let e = Either::One(X(Y)); + | - captured outer variable ... -LL | match e { - | ^ help: consider borrowing here: `&e` -... -LL | Either::One(_t) => (), - | -- - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match e { + | | ^ help: consider borrowing here: `&e` +... | +LL | | Either::One(_t) => (), + | | -- + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `x.0`, as `x` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:123:25 | -LL | let x = X(Y); - | - captured outer variable +LL | let x = X(Y); + | - captured outer variable ... -LL | let X(mut _t) = x; - | ------ ^ help: consider borrowing here: `&x` - | | - | data moved here - | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | let X(mut _t) = x; + | | ------ ^ help: consider borrowing here: `&x` + | | | + | | data moved here + | | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:127:38 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | if let Either::One(mut _t) = em { } - | ------ ^^ help: consider borrowing here: `&em` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | if let Either::One(mut _t) = em { } + | | ------ ^^ help: consider borrowing here: `&em` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:131:41 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | while let Either::One(mut _t) = em { } - | ------ ^^ help: consider borrowing here: `&em` - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | while let Either::One(mut _t) = em { } + | | ------ ^^ help: consider borrowing here: `&em` + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:135:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | match em { - | ^^ help: consider borrowing here: `&em` -... -LL | Either::One(mut _t) - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match em { + | | ^^ help: consider borrowing here: `&em` +... | +LL | | Either::One(mut _t) + | | ------ + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:142:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | match em { - | ^^ help: consider borrowing here: `&em` -... -LL | Either::One(mut _t) => (), - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match em { + | | ^^ help: consider borrowing here: `&em` +... | +LL | | Either::One(mut _t) => (), + | | ------ + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error[E0507]: cannot move out of `em.0`, as `em` is a captured variable in an `FnMut` closure --> $DIR/move-into-closure.rs:150:15 | -LL | let mut em = Either::One(X(Y)); - | ------ captured outer variable +LL | let mut em = Either::One(X(Y)); + | ------ captured outer variable ... -LL | match em { - | ^^ help: consider borrowing here: `&em` -... -LL | Either::One(mut _t) => (), - | ------ - | | - | data moved here - | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +LL | consume_fnmut(|| { + | ___________________- +LL | | let X(_t) = x; +LL | | +LL | | +... | +LL | | match em { + | | ^^ help: consider borrowing here: `&em` +... | +LL | | Either::One(mut _t) => (), + | | ------ + | | | + | | data moved here + | | move occurs because `_t` has type `X`, which does not implement the `Copy` trait +... | +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error: aborting due to 21 previous errors diff --git a/src/test/ui/suggestions/option-content-move2.stderr b/src/test/ui/suggestions/option-content-move2.stderr index cfbee1518cd..a0ce7d05b4d 100644 --- a/src/test/ui/suggestions/option-content-move2.stderr +++ b/src/test/ui/suggestions/option-content-move2.stderr @@ -1,17 +1,22 @@ error[E0507]: cannot move out of `var`, a captured variable in an `FnMut` closure --> $DIR/option-content-move2.rs:9:9 | -LL | let mut var = None; - | ------- captured outer variable -... -LL | move || { - | ^^^^^^^ move out of `var` occurs here -LL | -LL | var = Some(NotCopyable); - | --- - | | - | move occurs because `var` has type `Option`, which does not implement the `Copy` trait - | move occurs due to use in closure +LL | let mut var = None; + | ------- captured outer variable +LL | func(|| { + | __________- +LL | | // Shouldn't suggest `move ||.as_ref()` here +LL | | move || { + | | ^^^^^^^ move out of `var` occurs here +LL | | +LL | | var = Some(NotCopyable); + | | --- + | | | + | | move occurs because `var` has type `Option`, which does not implement the `Copy` trait + | | move occurs due to use in closure +LL | | } +LL | | }); + | |_____- captured by this `FnMut` closure error: aborting due to previous error diff --git a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr index f8c90176ff1..482d3e44fe4 100644 --- a/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr +++ b/src/test/ui/unboxed-closures/unboxed-closure-illegal-move.stderr @@ -4,7 +4,10 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn(|| drop(x)); - | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | --------^- + | | | + | | move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | captured by this `Fn` closure error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:19:35 @@ -12,7 +15,10 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn_mut(|| drop(x)); - | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | --------^- + | | | + | | move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | captured by this `FnMut` closure error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure --> $DIR/unboxed-closure-illegal-move.rs:28:36 @@ -20,7 +26,10 @@ error[E0507]: cannot move out of `x`, a captured variable in an `Fn` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn(move || drop(x)); - | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | -------------^- + | | | + | | move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | captured by this `Fn` closure error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure --> $DIR/unboxed-closure-illegal-move.rs:32:40 @@ -28,7 +37,10 @@ error[E0507]: cannot move out of `x`, a captured variable in an `FnMut` closure LL | let x = Box::new(0); | - captured outer variable LL | let f = to_fn_mut(move || drop(x)); - | ^ move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | -------------^- + | | | + | | move occurs because `x` has type `Box`, which does not implement the `Copy` trait + | captured by this `FnMut` closure error: aborting due to 4 previous errors From 4840f67fcbe02fe6428a0a29bcf329401242b739 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Tue, 14 Sep 2021 18:29:38 -0700 Subject: [PATCH 04/14] Add chown functions to std::os::unix::fs to change the owner and group of files This is a straightforward wrapper that uses the existing helpers for C string handling and errno handling. Having this available is convenient for UNIX utility programs written in Rust, and avoids having to call unsafe functions like `libc::chown` directly and handle errors manually, in a program that may otherwise be entirely safe code. In addition, these functions provide a more Rustic interface by accepting appropriate traits and using `None` rather than `-1`. --- library/std/src/os/unix/fs.rs | 70 ++++++++++++++++++++++++++++++++++ library/std/src/sys/unix/fs.rs | 17 +++++++++ 2 files changed, 87 insertions(+) diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index 6cf37f23c57..c26f6a182b7 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -5,6 +5,7 @@ use super::platform::fs::MetadataExt as _; use crate::fs::{self, OpenOptions, Permissions}; use crate::io; +use crate::os::unix::io::{AsFd, AsRawFd}; use crate::path::Path; use crate::sys; use crate::sys_common::{AsInner, AsInnerMut, FromInner}; @@ -924,6 +925,75 @@ fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { } } +/// Change the owner and group of the specified path. +/// +/// Specifying either the uid or gid as `None` will leave it unchanged. +/// +/// Changing the owner typically requires privileges, such as root or a specific capability. +/// Changing the group typically requires either being the owner and a member of the group, or +/// having privileges. +/// +/// If called on a symbolic link, this will change the owner and group of the link target. To +/// change the owner and group of the link itself, see [`lchown`]. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(unix_chown)] +/// use std::os::unix::fs; +/// +/// fn main() -> std::io::Result<()> { +/// fs::chown("/sandbox", Some(0), Some(0))?; +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_chown", issue = "none")] +pub fn chown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { + sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) +} + +/// Change the owner and group of the file referenced by the specified open file descriptor. +/// +/// For semantics and required privileges, see [`chown`]. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(unix_chown)] +/// use std::os::unix::fs; +/// +/// fn main() -> std::io::Result<()> { +/// let f = std::fs::File::open("/file")?; +/// fs::fchown(f, Some(0), Some(0))?; +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_chown", issue = "none")] +pub fn fchown(fd: F, uid: Option, gid: Option) -> io::Result<()> { + sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) +} + +/// Change the owner and group of the specified path, without dereferencing symbolic links. +/// +/// Identical to [`chown`], except that if called on a symbolic link, this will change the owner +/// and group of the link itself rather than the owner and group of the link target. +/// +/// # Examples +/// +/// ```no_run +/// #![feature(unix_chown)] +/// use std::os::unix::fs; +/// +/// fn main() -> std::io::Result<()> { +/// fs::lchown("/symlink", Some(0), Some(0))?; +/// Ok(()) +/// } +/// ``` +#[unstable(feature = "unix_chown", issue = "none")] +pub fn lchown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { + sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) +} + /// Change the root directory of the current process to the specified path. /// /// This typically requires privileges, such as root or a specific capability. diff --git a/library/std/src/sys/unix/fs.rs b/library/std/src/sys/unix/fs.rs index 6d7524a733a..a4fff9b2e64 100644 --- a/library/std/src/sys/unix/fs.rs +++ b/library/std/src/sys/unix/fs.rs @@ -1416,6 +1416,23 @@ fn fclonefileat( Ok(bytes_copied as u64) } +pub fn chown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { + let path = cstr(path)?; + cvt(unsafe { libc::chown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })?; + Ok(()) +} + +pub fn fchown(fd: c_int, uid: u32, gid: u32) -> io::Result<()> { + cvt(unsafe { libc::fchown(fd, uid as libc::uid_t, gid as libc::gid_t) })?; + Ok(()) +} + +pub fn lchown(path: &Path, uid: u32, gid: u32) -> io::Result<()> { + let path = cstr(path)?; + cvt(unsafe { libc::lchown(path.as_ptr(), uid as libc::uid_t, gid as libc::gid_t) })?; + Ok(()) +} + #[cfg(not(any(target_os = "fuchsia", target_os = "vxworks")))] pub fn chroot(dir: &Path) -> io::Result<()> { let dir = cstr(dir)?; From 862d89e3b5ba092d95586fc2a33b23d1c8672087 Mon Sep 17 00:00:00 2001 From: Josh Triplett Date: Wed, 15 Sep 2021 13:09:54 -0700 Subject: [PATCH 05/14] Add tracking issue for unix_chown --- library/std/src/os/unix/fs.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/library/std/src/os/unix/fs.rs b/library/std/src/os/unix/fs.rs index c26f6a182b7..30eead9b059 100644 --- a/library/std/src/os/unix/fs.rs +++ b/library/std/src/os/unix/fs.rs @@ -947,7 +947,7 @@ fn mode(&mut self, mode: u32) -> &mut fs::DirBuilder { /// Ok(()) /// } /// ``` -#[unstable(feature = "unix_chown", issue = "none")] +#[unstable(feature = "unix_chown", issue = "88989")] pub fn chown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { sys::fs::chown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) } @@ -968,7 +968,7 @@ pub fn chown>(dir: P, uid: Option, gid: Option) -> io:: /// Ok(()) /// } /// ``` -#[unstable(feature = "unix_chown", issue = "none")] +#[unstable(feature = "unix_chown", issue = "88989")] pub fn fchown(fd: F, uid: Option, gid: Option) -> io::Result<()> { sys::fs::fchown(fd.as_fd().as_raw_fd(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) } @@ -989,7 +989,7 @@ pub fn fchown(fd: F, uid: Option, gid: Option) -> io::Result< /// Ok(()) /// } /// ``` -#[unstable(feature = "unix_chown", issue = "none")] +#[unstable(feature = "unix_chown", issue = "88989")] pub fn lchown>(dir: P, uid: Option, gid: Option) -> io::Result<()> { sys::fs::lchown(dir.as_ref(), uid.unwrap_or(u32::MAX), gid.unwrap_or(u32::MAX)) } From 11c0e58c7489df3f71c3aebe04ad6d1b6a9f6262 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Tue, 14 Sep 2021 19:14:37 +0100 Subject: [PATCH 06/14] Allow `panic!("{}", computed_str)` in const fn. --- .../src/const_eval/machine.rs | 9 ++- .../src/transform/check_consts/check.rs | 13 +++++ .../src/transform/check_consts/mod.rs | 1 + compiler/rustc_hir/src/lang_items.rs | 1 + compiler/rustc_span/src/symbol.rs | 1 + library/core/src/panic.rs | 9 +++ library/core/src/panicking.rs | 7 +++ library/std/src/lib.rs | 1 + library/std/src/panic.rs | 6 +- library/std/src/rt.rs | 1 + src/test/ui/consts/const-eval/const_panic.rs | 8 ++- .../ui/consts/const-eval/const_panic.stderr | 50 ++++++++++------ .../ui/consts/const-eval/const_panic_2021.rs | 16 +++-- .../consts/const-eval/const_panic_2021.stderr | 58 ++++++++++++------- 14 files changed, 135 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_const_eval/src/const_eval/machine.rs b/compiler/rustc_const_eval/src/const_eval/machine.rs index 8a90686b900..ae20f6f97b2 100644 --- a/compiler/rustc_const_eval/src/const_eval/machine.rs +++ b/compiler/rustc_const_eval/src/const_eval/machine.rs @@ -36,12 +36,17 @@ fn hook_panic_fn( let def_id = instance.def_id(); if Some(def_id) == self.tcx.lang_items().panic_fn() || Some(def_id) == self.tcx.lang_items().panic_str() + || Some(def_id) == self.tcx.lang_items().panic_display() || Some(def_id) == self.tcx.lang_items().begin_panic_fn() { - // &str + // &str or &&str assert!(args.len() == 1); - let msg_place = self.deref_operand(&args[0])?; + let mut msg_place = self.deref_operand(&args[0])?; + while msg_place.layout.ty.is_ref() { + msg_place = self.deref_operand(&msg_place.into())?; + } + let msg = Symbol::intern(self.read_str(&msg_place)?); let span = self.find_closest_untracked_caller_location(); let (file, line, col) = self.location_triple_for_span(span); diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 02b317b8981..038041cdbfb 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -888,6 +888,10 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location if is_lang_panic_fn(tcx, callee) { self.check_op(ops::Panic); + // `begin_panic` and `panic_display` are generic functions that accept + // types other than str. Check to enforce that only str can be used in + // const-eval. + // const-eval of the `begin_panic` fn assumes the argument is `&str` if Some(callee) == tcx.lang_items().begin_panic_fn() { match args[0].ty(&self.ccx.body.local_decls, tcx).kind() { @@ -896,6 +900,15 @@ fn visit_terminator(&mut self, terminator: &Terminator<'tcx>, location: Location } } + // const-eval of the `panic_display` fn assumes the argument is `&&str` + if Some(callee) == tcx.lang_items().panic_display() { + match args[0].ty(&self.ccx.body.local_decls, tcx).kind() { + ty::Ref(_, ty, _) if matches!(ty.kind(), ty::Ref(_, ty, _) if ty.is_str()) => + {} + _ => self.check_op(ops::PanicNonStr), + } + } + return; } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index a5cb0f4e14b..d1fd3ceaa58 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -79,6 +79,7 @@ pub fn is_lang_panic_fn(tcx: TyCtxt<'tcx>, def_id: DefId) -> bool { // Keep in sync with what that function handles! Some(def_id) == tcx.lang_items().panic_fn() || Some(def_id) == tcx.lang_items().panic_str() + || Some(def_id) == tcx.lang_items().panic_display() || Some(def_id) == tcx.lang_items().begin_panic_fn() || Some(def_id) == tcx.lang_items().panic_fmt() || Some(def_id) == tcx.lang_items().begin_panic_fmt() diff --git a/compiler/rustc_hir/src/lang_items.rs b/compiler/rustc_hir/src/lang_items.rs index b85ed0cb4bb..d69a2470540 100644 --- a/compiler/rustc_hir/src/lang_items.rs +++ b/compiler/rustc_hir/src/lang_items.rs @@ -283,6 +283,7 @@ pub fn extract<'a, F>(check_name: F, attrs: &'a [ast::Attribute]) -> Option<(Sym // a weak lang item, but do not have it defined. Panic, sym::panic, panic_fn, Target::Fn, GenericRequirement::None; PanicFmt, sym::panic_fmt, panic_fmt, Target::Fn, GenericRequirement::None; + PanicDisplay, sym::panic_display, panic_display, Target::Fn, GenericRequirement::None; PanicStr, sym::panic_str, panic_str, Target::Fn, GenericRequirement::None; ConstPanicFmt, sym::const_panic_fmt, const_panic_fmt, Target::Fn, GenericRequirement::None; PanicBoundsCheck, sym::panic_bounds_check, panic_bounds_check_fn, Target::Fn, GenericRequirement::None; diff --git a/compiler/rustc_span/src/symbol.rs b/compiler/rustc_span/src/symbol.rs index c816d060456..fb6fdcf28de 100644 --- a/compiler/rustc_span/src/symbol.rs +++ b/compiler/rustc_span/src/symbol.rs @@ -923,6 +923,7 @@ panic_2021, panic_abort, panic_bounds_check, + panic_display, panic_fmt, panic_handler, panic_impl, diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index 463bec37265..7a8b04d6f3c 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -27,9 +27,14 @@ ($msg:literal $(,)?) => ( $crate::panicking::panic($msg) ), + // Use `panic_str` instead of `panic_display::<&str>` for non_fmt_panic lint. ($msg:expr $(,)?) => ( $crate::panicking::panic_str($msg) ), + // Special-case the single-argument case for const_panic. + ("{}", $arg:expr $(,)?) => ( + $crate::panicking::panic_display(&$arg) + ), ($fmt:expr, $($arg:tt)+) => ( $crate::panicking::panic_fmt($crate::const_format_args!($fmt, $($arg)+)) ), @@ -44,6 +49,10 @@ () => ( $crate::panicking::panic("explicit panic") ), + // Special-case the single-argument case for const_panic. + ("{}", $arg:expr $(,)?) => ( + $crate::panicking::panic_display(&$arg) + ), ($($t:tt)+) => ( $crate::panicking::panic_fmt($crate::const_format_args!($($t)+)) ), diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 02f32675247..a6aa4bf43c8 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -60,6 +60,13 @@ pub fn panic_str(expr: &str) -> ! { panic_fmt(format_args!("{}", expr)); } +#[inline] +#[track_caller] +#[cfg_attr(not(bootstrap), lang = "panic_display")] // needed for const-evaluated panics +pub fn panic_display(x: &T) -> ! { + panic_fmt(format_args!("{}", *x)); +} + #[cold] #[cfg_attr(not(feature = "panic_immediate_abort"), inline(never))] #[track_caller] diff --git a/library/std/src/lib.rs b/library/std/src/lib.rs index 83c6ba0e6ea..559d2672a0d 100644 --- a/library/std/src/lib.rs +++ b/library/std/src/lib.rs @@ -258,6 +258,7 @@ #![feature(const_trait_impl)] #![feature(container_error_extra)] #![feature(core_intrinsics)] +#![feature(core_panic)] #![feature(custom_test_frameworks)] #![feature(decl_macro)] #![feature(doc_cfg)] diff --git a/library/std/src/panic.rs b/library/std/src/panic.rs index c1c03958497..21e9669c110 100644 --- a/library/std/src/panic.rs +++ b/library/std/src/panic.rs @@ -10,7 +10,7 @@ #[doc(hidden)] #[unstable(feature = "edition_panic", issue = "none", reason = "use panic!() instead")] -#[allow_internal_unstable(libstd_sys_internals, const_format_args)] +#[allow_internal_unstable(libstd_sys_internals, const_format_args, core_panic)] #[cfg_attr(not(test), rustc_diagnostic_item = "std_panic_2015_macro")] #[rustc_macro_transparency = "semitransparent"] pub macro panic_2015 { @@ -20,6 +20,10 @@ ($msg:expr $(,)?) => ({ $crate::rt::begin_panic($msg) }), + // Special-case the single-argument case for const_panic. + ("{}", $arg:expr $(,)?) => ({ + $crate::rt::panic_display(&$arg) + }), ($fmt:expr, $($arg:tt)+) => ({ $crate::rt::begin_panic_fmt(&$crate::const_format_args!($fmt, $($arg)+)) }), diff --git a/library/std/src/rt.rs b/library/std/src/rt.rs index 72e6c23ee49..b4f2adf938b 100644 --- a/library/std/src/rt.rs +++ b/library/std/src/rt.rs @@ -16,6 +16,7 @@ // Re-export some of our utilities which are expected by other crates. pub use crate::panicking::{begin_panic, begin_panic_fmt, panic_count}; +pub use core::panicking::panic_display; // To reduce the generated code of the new `lang_start`, this function is doing // the real work. diff --git a/src/test/ui/consts/const-eval/const_panic.rs b/src/test/ui/consts/const-eval/const_panic.rs index e4455d86a14..100faded079 100644 --- a/src/test/ui/consts/const-eval/const_panic.rs +++ b/src/test/ui/consts/const-eval/const_panic.rs @@ -15,10 +15,13 @@ const X: () = std::unimplemented!(); //~^ ERROR evaluation of constant value failed -// + const W: () = std::panic!(MSG); //~^ ERROR evaluation of constant value failed +const W2: () = std::panic!("{}", MSG); +//~^ ERROR evaluation of constant value failed + const Z_CORE: () = core::panic!("cheese"); //~^ ERROR evaluation of constant value failed @@ -33,3 +36,6 @@ const W_CORE: () = core::panic!(MSG); //~^ ERROR evaluation of constant value failed + +const W2_CORE: () = core::panic!("{}", MSG); +//~^ ERROR evaluation of constant value failed diff --git a/src/test/ui/consts/const-eval/const_panic.stderr b/src/test/ui/consts/const-eval/const_panic.stderr index c0c749ede56..e98e4a506c0 100644 --- a/src/test/ui/consts/const-eval/const_panic.stderr +++ b/src/test/ui/consts/const-eval/const_panic.stderr @@ -39,45 +39,61 @@ LL | const W: () = std::panic!(MSG); = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:22:20 + --> $DIR/const_panic.rs:22:16 + | +LL | const W2: () = std::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:22:16 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:25:20 | LL | const Z_CORE: () = core::panic!("cheese"); - | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:22:20 + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'cheese', $DIR/const_panic.rs:25:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:25:21 + --> $DIR/const_panic.rs:28:21 | LL | const Z2_CORE: () = core::panic!(); - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:25:21 - | - = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) - -error[E0080]: evaluation of constant value failed - --> $DIR/const_panic.rs:28:20 - | -LL | const Y_CORE: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:28:20 + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic.rs:28:21 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed --> $DIR/const_panic.rs:31:20 | -LL | const X_CORE: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:31:20 +LL | const Y_CORE: () = core::unreachable!(); + | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic.rs:31:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed --> $DIR/const_panic.rs:34:20 | -LL | const W_CORE: () = core::panic!(MSG); - | ^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:34:20 +LL | const X_CORE: () = core::unimplemented!(); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic.rs:34:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 10 previous errors +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:37:20 + | +LL | const W_CORE: () = core::panic!(MSG); + | ^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:37:20 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic.rs:40:21 + | +LL | const W2_CORE: () = core::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic.rs:40:21 + | + = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 12 previous errors For more information about this error, try `rustc --explain E0080`. diff --git a/src/test/ui/consts/const-eval/const_panic_2021.rs b/src/test/ui/consts/const-eval/const_panic_2021.rs index daef34cd6a3..9b8652a776e 100644 --- a/src/test/ui/consts/const-eval/const_panic_2021.rs +++ b/src/test/ui/consts/const-eval/const_panic_2021.rs @@ -2,6 +2,8 @@ #![feature(const_panic)] #![crate_type = "lib"] +const MSG: &str = "hello"; + const A: () = std::panic!("blåhaj"); //~^ ERROR evaluation of constant value failed @@ -14,14 +16,20 @@ const D: () = std::unimplemented!(); //~^ ERROR evaluation of constant value failed -const E: () = core::panic!("shark"); +const E: () = std::panic!("{}", MSG); //~^ ERROR evaluation of constant value failed -const F: () = core::panic!(); +const A_CORE: () = core::panic!("shark"); //~^ ERROR evaluation of constant value failed -const G: () = core::unreachable!(); +const B_CORE: () = core::panic!(); //~^ ERROR evaluation of constant value failed -const H: () = core::unimplemented!(); +const C_CORE: () = core::unreachable!(); +//~^ ERROR evaluation of constant value failed + +const D_CORE: () = core::unimplemented!(); +//~^ ERROR evaluation of constant value failed + +const E_CORE: () = core::panic!("{}", MSG); //~^ ERROR evaluation of constant value failed diff --git a/src/test/ui/consts/const-eval/const_panic_2021.stderr b/src/test/ui/consts/const-eval/const_panic_2021.stderr index c1bdab3693d..9eb241ae8e5 100644 --- a/src/test/ui/consts/const-eval/const_panic_2021.stderr +++ b/src/test/ui/consts/const-eval/const_panic_2021.stderr @@ -1,67 +1,83 @@ error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:5:15 + --> $DIR/const_panic_2021.rs:7:15 | LL | const A: () = std::panic!("blåhaj"); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'blåhaj', $DIR/const_panic_2021.rs:5:15 + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'blåhaj', $DIR/const_panic_2021.rs:7:15 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:8:15 + --> $DIR/const_panic_2021.rs:10:15 | LL | const B: () = std::panic!(); - | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:8:15 + | ^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:10:15 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:11:15 + --> $DIR/const_panic_2021.rs:13:15 | LL | const C: () = std::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:11:15 + | ^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:13:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:14:15 + --> $DIR/const_panic_2021.rs:16:15 | LL | const D: () = std::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:14:15 + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:16:15 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:17:15 + --> $DIR/const_panic_2021.rs:19:15 | -LL | const E: () = core::panic!("shark"); - | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'shark', $DIR/const_panic_2021.rs:17:15 +LL | const E: () = std::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:19:15 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:20:15 + --> $DIR/const_panic_2021.rs:22:20 | -LL | const F: () = core::panic!(); - | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:20:15 +LL | const A_CORE: () = core::panic!("shark"); + | ^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'shark', $DIR/const_panic_2021.rs:22:20 | = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:23:15 + --> $DIR/const_panic_2021.rs:25:20 | -LL | const G: () = core::unreachable!(); - | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:23:15 +LL | const B_CORE: () = core::panic!(); + | ^^^^^^^^^^^^^^ the evaluated program panicked at 'explicit panic', $DIR/const_panic_2021.rs:25:20 + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:28:20 + | +LL | const C_CORE: () = core::unreachable!(); + | ^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'internal error: entered unreachable code', $DIR/const_panic_2021.rs:28:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0080]: evaluation of constant value failed - --> $DIR/const_panic_2021.rs:26:15 + --> $DIR/const_panic_2021.rs:31:20 | -LL | const H: () = core::unimplemented!(); - | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:26:15 +LL | const D_CORE: () = core::unimplemented!(); + | ^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'not implemented', $DIR/const_panic_2021.rs:31:20 | = note: this error originates in the macro `$crate::panic::panic_2015` (in Nightly builds, run with -Z macro-backtrace for more info) -error: aborting due to 8 previous errors +error[E0080]: evaluation of constant value failed + --> $DIR/const_panic_2021.rs:34:20 + | +LL | const E_CORE: () = core::panic!("{}", MSG); + | ^^^^^^^^^^^^^^^^^^^^^^^ the evaluated program panicked at 'hello', $DIR/const_panic_2021.rs:34:20 + | + = note: this error originates in the macro `$crate::panic::panic_2021` (in Nightly builds, run with -Z macro-backtrace for more info) + +error: aborting due to 10 previous errors For more information about this error, try `rustc --explain E0080`. From 9f7e281d47f27c24a59b30cae30c20435be4083c Mon Sep 17 00:00:00 2001 From: Vishad Goyal Date: Thu, 16 Sep 2021 19:28:03 +0530 Subject: [PATCH 07/14] delay error for enabling unstable lib features If #![feature] is used outside the nightly channel for only lib features, the check will be delayed to the stability pass after parsing. This is done so that appropriate help messages can be shown if the #![feature] has been used needlessly --- compiler/rustc_ast_passes/src/feature_gate.rs | 6 ++++++ compiler/rustc_passes/src/stability.rs | 10 ++++++++++ 2 files changed, 16 insertions(+) diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index 30bc4edd7e6..06e9d9ed329 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -702,10 +702,16 @@ macro_rules! gate_all { } fn maybe_stage_features(sess: &Session, krate: &ast::Crate) { + // checks if `#![feature]` has been used to enable any lang feature + // does not check the same for lib features unless there's at least one + // declared lang feature use rustc_errors::Applicability; if !sess.opts.unstable_features.is_nightly_build() { let lang_features = &sess.features_untracked().declared_lang_features; + if lang_features.len() == 0 { + return; + } for attr in krate.attrs.iter().filter(|attr| attr.has_name(sym::feature)) { let mut err = struct_span_err!( sess.parse_sess.span_diagnostic, diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index b7e43b7785d..d7c354aeb49 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -929,6 +929,16 @@ pub fn check_unused_or_stable_features(tcx: TyCtxt<'_>) { let declared_lib_features = &tcx.features().declared_lib_features; let mut remaining_lib_features = FxHashMap::default(); for (feature, span) in declared_lib_features { + if !tcx.sess.opts.unstable_features.is_nightly_build() { + struct_span_err!( + tcx.sess, + *span, + E0554, + "`#![feature]` may not be used on the {} release channel", + env!("CFG_RELEASE_CHANNEL") + ) + .emit(); + } if remaining_lib_features.contains_key(&feature) { // Warn if the user enables a lib feature multiple times. duplicate_feature_err(tcx.sess, *span, *feature); From 58765d61ee1762ce0dd9565074000cb9c1267a02 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 18 Jun 2021 10:22:23 +0900 Subject: [PATCH 08/14] Emit clearer diagnostics for parens around `for` loop heads --- compiler/rustc_parse/src/parser/diagnostics.rs | 5 +++-- src/test/ui/parser/recover-for-loop-parens-around-head.rs | 2 +- .../ui/parser/recover-for-loop-parens-around-head.stderr | 7 +++---- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 4fccfc287fd..ab7478c7e5f 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1346,8 +1346,9 @@ pub(super) fn recover_parens_around_for_head( .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap()) .unwrap_or_else(|_| pprust::pat_to_string(&pat)); - self.struct_span_err(self.prev_token.span, "unexpected closing `)`") - .span_label(begin_par_sp, "opening `(`") + let sp = MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]); + + self.struct_span_err(sp, "unexpected parenthesis surrounding `for` loop head") .span_suggestion( begin_par_sp.to(self.prev_token.span), "remove parenthesis in `for` loop", diff --git a/src/test/ui/parser/recover-for-loop-parens-around-head.rs b/src/test/ui/parser/recover-for-loop-parens-around-head.rs index 779e1646344..8080dbc332a 100644 --- a/src/test/ui/parser/recover-for-loop-parens-around-head.rs +++ b/src/test/ui/parser/recover-for-loop-parens-around-head.rs @@ -9,7 +9,7 @@ fn main() { for ( elem in vec ) { //~^ ERROR expected one of `)`, `,`, `@`, or `|`, found keyword `in` - //~| ERROR unexpected closing `)` + //~| ERROR unexpected parenthesis surrounding `for` loop head const RECOVERY_WITNESS: () = 0; //~ ERROR mismatched types } } diff --git a/src/test/ui/parser/recover-for-loop-parens-around-head.stderr b/src/test/ui/parser/recover-for-loop-parens-around-head.stderr index e97cf544ac2..98f6b5b884b 100644 --- a/src/test/ui/parser/recover-for-loop-parens-around-head.stderr +++ b/src/test/ui/parser/recover-for-loop-parens-around-head.stderr @@ -4,13 +4,12 @@ error: expected one of `)`, `,`, `@`, or `|`, found keyword `in` LL | for ( elem in vec ) { | ^^ expected one of `)`, `,`, `@`, or `|` -error: unexpected closing `)` - --> $DIR/recover-for-loop-parens-around-head.rs:10:23 +error: unexpected parenthesis surrounding `for` loop head + --> $DIR/recover-for-loop-parens-around-head.rs:10:9 | LL | for ( elem in vec ) { - | --------------^ + | ^-------------^ | | - | opening `(` | help: remove parenthesis in `for` loop: `elem in vec` error[E0308]: mismatched types From e9bf73cb2b025e188787683f1423177a9102d260 Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 17 Sep 2021 13:39:26 +0900 Subject: [PATCH 09/14] Use `multipart_suggestion` --- .../rustc_parse/src/parser/diagnostics.rs | 32 ++++++++----------- compiler/rustc_parse/src/parser/expr.rs | 2 +- ...recover-for-loop-parens-around-head.stderr | 10 ++++-- 3 files changed, 21 insertions(+), 23 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index ab7478c7e5f..88b5f89f680 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1334,31 +1334,25 @@ pub(super) fn try_macro_suggestion(&mut self) -> PResult<'a, P> { pub(super) fn recover_parens_around_for_head( &mut self, pat: P, - expr: &Expr, begin_paren: Option, ) -> P { match (&self.token.kind, begin_paren) { (token::CloseDelim(token::Paren), Some(begin_par_sp)) => { self.bump(); - let pat_str = self - // Remove the `(` from the span of the pattern: - .span_to_snippet(pat.span.trim_start(begin_par_sp).unwrap()) - .unwrap_or_else(|_| pprust::pat_to_string(&pat)); - - let sp = MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]); - - self.struct_span_err(sp, "unexpected parenthesis surrounding `for` loop head") - .span_suggestion( - begin_par_sp.to(self.prev_token.span), - "remove parenthesis in `for` loop", - format!("{} in {}", pat_str, pprust::expr_to_string(&expr)), - // With e.g. `for (x) in y)` this would replace `(x) in y)` - // with `x) in y)` which is syntactically invalid. - // However, this is prevented before we get here. - Applicability::MachineApplicable, - ) - .emit(); + self.struct_span_err( + MultiSpan::from_spans(vec![begin_par_sp, self.prev_token.span]), + "unexpected parenthesis surrounding `for` loop head", + ) + .multipart_suggestion( + "remove parenthesis in `for` loop", + vec![(begin_par_sp, String::new()), (self.prev_token.span, String::new())], + // With e.g. `for (x) in y)` this would replace `(x) in y)` + // with `x) in y)` which is syntactically invalid. + // However, this is prevented before we get here. + Applicability::MachineApplicable, + ) + .emit(); // Unwrap `(pat)` into `pat` to avoid the `unused_parens` lint. pat.and_then(|pat| match pat.kind { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 737f1d9cbb1..d8f9fc9179e 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -2042,7 +2042,7 @@ fn parse_for_expr( self.check_for_for_in_in_typo(self.prev_token.span); let expr = self.parse_expr_res(Restrictions::NO_STRUCT_LITERAL, None)?; - let pat = self.recover_parens_around_for_head(pat, &expr, begin_paren); + let pat = self.recover_parens_around_for_head(pat, begin_paren); let (iattrs, loop_block) = self.parse_inner_attrs_and_block()?; attrs.extend(iattrs); diff --git a/src/test/ui/parser/recover-for-loop-parens-around-head.stderr b/src/test/ui/parser/recover-for-loop-parens-around-head.stderr index 98f6b5b884b..21991348327 100644 --- a/src/test/ui/parser/recover-for-loop-parens-around-head.stderr +++ b/src/test/ui/parser/recover-for-loop-parens-around-head.stderr @@ -8,9 +8,13 @@ error: unexpected parenthesis surrounding `for` loop head --> $DIR/recover-for-loop-parens-around-head.rs:10:9 | LL | for ( elem in vec ) { - | ^-------------^ - | | - | help: remove parenthesis in `for` loop: `elem in vec` + | ^ ^ + | +help: remove parenthesis in `for` loop + | +LL - for ( elem in vec ) { +LL + for elem in vec { + | error[E0308]: mismatched types --> $DIR/recover-for-loop-parens-around-head.rs:13:38 From 9342be5538ad5c97e8d2496e1cbbf2530d377e5e Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Thu, 29 Jul 2021 05:49:56 +0900 Subject: [PATCH 10/14] Recover invalid assoc type bounds using `==` --- .../rustc_parse/src/parser/diagnostics.rs | 14 +++++++++- .../ui/const-generics/issues/issue-87493.rs | 14 ++++++++++ .../const-generics/issues/issue-87493.stderr | 26 +++++++++++++++++++ 3 files changed, 53 insertions(+), 1 deletion(-) create mode 100644 src/test/ui/const-generics/issues/issue-87493.rs create mode 100644 src/test/ui/const-generics/issues/issue-87493.stderr diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 4fccfc287fd..39651bd5e67 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1955,7 +1955,19 @@ pub fn recover_const_arg( } match self.parse_expr_res(Restrictions::CONST_EXPR, None) { Ok(expr) => { - if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() { + // Find a mistake like `MyTrait`. + if token::EqEq == snapshot.token.kind { + err.span_suggestion( + snapshot.token.span, + "replace `==` with `=`", + "=".to_string(), + Applicability::MaybeIncorrect, + ); + let value = self.mk_expr_err(expr.span); + err.emit(); + return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); + } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() + { // Avoid the following output by checking that we consumed a full const arg: // help: expressions must be enclosed in braces to be used as const generic // arguments diff --git a/src/test/ui/const-generics/issues/issue-87493.rs b/src/test/ui/const-generics/issues/issue-87493.rs new file mode 100644 index 00000000000..d8599ab22a3 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-87493.rs @@ -0,0 +1,14 @@ +pub trait MyTrait { + type Assoc; +} + +pub fn foo(_s: S, _t: T) +where + S: MyTrait, + T: MyTrait, + //~^ ERROR: expected one of `,` or `>`, found `==` + //~| ERROR: this trait takes 0 generic arguments but 1 generic argument was supplied +{ +} + +fn main() {} diff --git a/src/test/ui/const-generics/issues/issue-87493.stderr b/src/test/ui/const-generics/issues/issue-87493.stderr new file mode 100644 index 00000000000..b1ac08b51b5 --- /dev/null +++ b/src/test/ui/const-generics/issues/issue-87493.stderr @@ -0,0 +1,26 @@ +error: expected one of `,` or `>`, found `==` + --> $DIR/issue-87493.rs:8:22 + | +LL | T: MyTrait, + | ^^ + | | + | expected one of `,` or `>` + | help: replace `==` with `=`: `=` + +error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied + --> $DIR/issue-87493.rs:8:8 + | +LL | T: MyTrait, + | ^^^^^^^------------------- help: remove these generics + | | + | expected 0 generic arguments + | +note: trait defined here, with 0 generic parameters + --> $DIR/issue-87493.rs:1:11 + | +LL | pub trait MyTrait { + | ^^^^^^^ + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0107`. From ee99bb393953c31169e89597ec893fd15a3ff4ee Mon Sep 17 00:00:00 2001 From: Yuki Okushi Date: Fri, 17 Sep 2021 14:10:41 +0900 Subject: [PATCH 11/14] Apply review comments --- compiler/rustc_parse/src/parser/diagnostics.rs | 4 ++-- src/test/ui/const-generics/issues/issue-87493.stderr | 10 ++++++---- 2 files changed, 8 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_parse/src/parser/diagnostics.rs b/compiler/rustc_parse/src/parser/diagnostics.rs index 39651bd5e67..1a77057939f 100644 --- a/compiler/rustc_parse/src/parser/diagnostics.rs +++ b/compiler/rustc_parse/src/parser/diagnostics.rs @@ -1959,11 +1959,11 @@ pub fn recover_const_arg( if token::EqEq == snapshot.token.kind { err.span_suggestion( snapshot.token.span, - "replace `==` with `=`", + "if you meant to use an associated type binding, replace `==` with `=`", "=".to_string(), Applicability::MaybeIncorrect, ); - let value = self.mk_expr_err(expr.span); + let value = self.mk_expr_err(start.to(expr.span)); err.emit(); return Ok(GenericArg::Const(AnonConst { id: ast::DUMMY_NODE_ID, value })); } else if token::Comma == self.token.kind || self.token.kind.should_end_const_arg() diff --git a/src/test/ui/const-generics/issues/issue-87493.stderr b/src/test/ui/const-generics/issues/issue-87493.stderr index b1ac08b51b5..8f92eeaffd1 100644 --- a/src/test/ui/const-generics/issues/issue-87493.stderr +++ b/src/test/ui/const-generics/issues/issue-87493.stderr @@ -2,10 +2,12 @@ error: expected one of `,` or `>`, found `==` --> $DIR/issue-87493.rs:8:22 | LL | T: MyTrait, - | ^^ - | | - | expected one of `,` or `>` - | help: replace `==` with `=`: `=` + | ^^ expected one of `,` or `>` + | +help: if you meant to use an associated type binding, replace `==` with `=` + | +LL | T: MyTrait, + | ~ error[E0107]: this trait takes 0 generic arguments but 1 generic argument was supplied --> $DIR/issue-87493.rs:8:8 From bc49c3b6516779acb5b0bf2eae6d1404ead216eb Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Sep 2021 17:20:37 +0200 Subject: [PATCH 12/14] Allow to pass "compiler" arguments to doc subcommand --- src/bootstrap/doc.rs | 54 ++++++++++++++++++++++++++++++++++++-------- 1 file changed, 44 insertions(+), 10 deletions(-) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index fbc7f19cb73..5a1593d7405 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -537,7 +537,7 @@ impl Step for Rustc { fn should_run(run: ShouldRun<'_>) -> ShouldRun<'_> { let builder = run.builder; - run.krate("rustc-main").default_condition(builder.config.docs) + run.krate("rustc-main").path("compiler").default_condition(builder.config.docs) } fn make_run(run: RunConfig<'_>) { @@ -553,9 +553,24 @@ fn make_run(run: RunConfig<'_>) { fn run(self, builder: &Builder<'_>) { let stage = self.stage; let target = self.target; + let mut is_explicit_request = false; builder.info(&format!("Documenting stage{} compiler ({})", stage, target)); - if !builder.config.compiler_docs { + let paths = builder + .paths + .iter() + .map(components_simplified) + .filter_map(|path| { + if path.get(0) == Some(&"compiler") { + is_explicit_request = true; + path.get(1).map(|p| p.to_owned()) + } else { + None + } + }) + .collect::>(); + + if !builder.config.compiler_docs && !is_explicit_request { builder.info("\tskipping - compiler/librustdoc docs disabled"); return; } @@ -603,15 +618,34 @@ fn run(self, builder: &Builder<'_>) { cargo.rustdocflag("--extern-html-root-url"); cargo.rustdocflag("ena=https://docs.rs/ena/latest/"); - // Find dependencies for top level crates. let mut compiler_crates = HashSet::new(); - for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] { - compiler_crates.extend( - builder - .in_tree_crates(root_crate, Some(target)) - .into_iter() - .map(|krate| krate.name), - ); + + if paths.is_empty() { + // Find dependencies for top level crates. + for root_crate in &["rustc_driver", "rustc_codegen_llvm", "rustc_codegen_ssa"] { + compiler_crates.extend( + builder + .in_tree_crates(root_crate, Some(target)) + .into_iter() + .map(|krate| krate.name), + ); + } + } else { + for root_crate in paths { + if !builder.src.join("compiler").join(&root_crate).exists() { + builder.info(&format!( + "\tskipping - compiler/{} (unknown compiler crate)", + root_crate + )); + } else { + compiler_crates.extend( + builder + .in_tree_crates(root_crate, Some(target)) + .into_iter() + .map(|krate| krate.name), + ); + } + } } for krate in &compiler_crates { From 57ee7a63ebc28e9ed645702fa152b8f35a0cd538 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Sun, 5 Sep 2021 17:24:09 +0200 Subject: [PATCH 13/14] Correctly handle "--open" option when building compiler docs --- src/bootstrap/doc.rs | 9 +++++++++ 1 file changed, 9 insertions(+) diff --git a/src/bootstrap/doc.rs b/src/bootstrap/doc.rs index 5a1593d7405..a1a954fdfce 100644 --- a/src/bootstrap/doc.rs +++ b/src/bootstrap/doc.rs @@ -648,15 +648,24 @@ fn run(self, builder: &Builder<'_>) { } } + let mut to_open = None; for krate in &compiler_crates { // Create all crate output directories first to make sure rustdoc uses // relative links. // FIXME: Cargo should probably do this itself. t!(fs::create_dir_all(out_dir.join(krate))); cargo.arg("-p").arg(krate); + if to_open.is_none() { + to_open = Some(krate); + } } builder.run(&mut cargo.into()); + // Let's open the first crate documentation page: + if let Some(krate) = to_open { + let index = out.join(krate).join("index.html"); + open(builder, &index); + } } } From cd3f4da244578a2ab4d17d10016c61b9191b21e4 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Wed, 15 Sep 2021 13:37:29 +0200 Subject: [PATCH 14/14] Add rustdoc version into the help popup --- src/librustdoc/html/render/write_shared.rs | 16 ++++++++++++---- src/librustdoc/html/static/css/rustdoc.css | 15 ++++++++++++--- src/librustdoc/html/static/css/themes/ayu.css | 4 ++-- src/librustdoc/html/static/css/themes/dark.css | 4 ++-- src/librustdoc/html/static/css/themes/light.css | 4 ++-- src/librustdoc/html/static/js/main.js | 9 +++++++++ 6 files changed, 39 insertions(+), 13 deletions(-) diff --git a/src/librustdoc/html/render/write_shared.rs b/src/librustdoc/html/render/write_shared.rs index 1dd0917699b..c1a83ad5820 100644 --- a/src/librustdoc/html/render/write_shared.rs +++ b/src/librustdoc/html/render/write_shared.rs @@ -268,10 +268,18 @@ fn add_background_image_to_css( // Maybe we can change the representation to move this out of main.js? write_minify( "main.js", - static_files::MAIN_JS.replace( - "/* INSERT THEMES HERE */", - &format!(" = {}", serde_json::to_string(&themes).unwrap()), - ), + static_files::MAIN_JS + .replace( + "/* INSERT THEMES HERE */", + &format!(" = {}", serde_json::to_string(&themes).unwrap()), + ) + .replace( + "/* INSERT RUSTDOC_VERSION HERE */", + &format!( + "rustdoc {}", + rustc_interface::util::version_str().unwrap_or("unknown version") + ), + ), cx, options, )?; diff --git a/src/librustdoc/html/static/css/rustdoc.css b/src/librustdoc/html/static/css/rustdoc.css index 2d4bfc62af6..eb7cc9309f4 100644 --- a/src/librustdoc/html/static/css/rustdoc.css +++ b/src/librustdoc/html/static/css/rustdoc.css @@ -928,15 +928,24 @@ body.blur > :not(#help) { display: block; margin-right: 0.5rem; } -#help > div > span { +#help span.top, #help span.bottom { + text-align: center; + display: block; + font-size: 18px; + +} +#help span.top { text-align: center; display: block; margin: 10px 0; - font-size: 18px; - border-bottom: 1px solid #ccc; + border-bottom: 1px solid; padding-bottom: 4px; margin-bottom: 6px; } +#help span.bottom { + clear: both; + border-top: 1px solid; +} #help dd { margin: 5px 35px; } #help .infos { padding-left: 0; } #help h1, #help h2 { margin-top: 0; } diff --git a/src/librustdoc/html/static/css/themes/ayu.css b/src/librustdoc/html/static/css/themes/ayu.css index eada8f4a04d..c79801e8308 100644 --- a/src/librustdoc/html/static/css/themes/ayu.css +++ b/src/librustdoc/html/static/css/themes/ayu.css @@ -286,8 +286,8 @@ details.undocumented > summary::before { border-radius: 4px; } -#help > div > span { - border-bottom-color: #5c6773; +#help span.bottom, #help span.top { + border-color: #5c6773; } .since { diff --git a/src/librustdoc/html/static/css/themes/dark.css b/src/librustdoc/html/static/css/themes/dark.css index d9348be6994..d2e54070acd 100644 --- a/src/librustdoc/html/static/css/themes/dark.css +++ b/src/librustdoc/html/static/css/themes/dark.css @@ -242,8 +242,8 @@ details.undocumented > summary::before { border-color: #bfbfbf; } -#help > div > span { - border-bottom-color: #bfbfbf; +#help span.bottom, #help span.top { + border-color: #bfbfbf; } #help dt { diff --git a/src/librustdoc/html/static/css/themes/light.css b/src/librustdoc/html/static/css/themes/light.css index 0ffe5929ea5..25d810560c1 100644 --- a/src/librustdoc/html/static/css/themes/light.css +++ b/src/librustdoc/html/static/css/themes/light.css @@ -232,8 +232,8 @@ details.undocumented > summary::before { border-color: #bfbfbf; } -#help > div > span { - border-bottom-color: #bfbfbf; +#help span.bottom, #help span.top { + border-color: #bfbfbf; } .since { diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 1eebd392564..e396fd9d288 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -911,6 +911,7 @@ function hideThemeButtonState() { }); var book_info = document.createElement("span"); + book_info.className = "top"; book_info.innerHTML = "You can find more information in \ the rustdoc book."; @@ -961,6 +962,14 @@ function hideThemeButtonState() { container.appendChild(div_shortcuts); container.appendChild(div_infos); + var rustdoc_version = document.createElement("span"); + rustdoc_version.className = "bottom"; + var rustdoc_version_code = document.createElement("code"); + rustdoc_version_code.innerText = "/* INSERT RUSTDOC_VERSION HERE */"; + rustdoc_version.appendChild(rustdoc_version_code); + + container.appendChild(rustdoc_version); + popup.appendChild(container); insertAfter(popup, searchState.outputElement()); // So that it's only built once and then it'll do nothing when called!