From de677b993fba6a2af9dbcbda0db1671f2d84f451 Mon Sep 17 00:00:00 2001 From: Kenny Goodin Date: Wed, 29 May 2019 18:58:54 -0400 Subject: [PATCH 01/12] Remove asterisk suggestion for move errors in borrowck As per issue #54985 removes the not useful suggestion to remove asterisk in move errors. Includes minor changes to tests in the `ui` suite to account for the removed suggestion. --- src/librustc_mir/borrow_check/move_errors.rs | 32 ++++--------------- src/test/ui/access-mode-in-closures.stderr | 2 +- .../ui/borrowck/borrowck-issue-2657-2.stderr | 2 +- .../borrowck-move-error-with-note.stderr | 2 +- .../borrowck-move-from-unsafe-ptr.stderr | 2 +- ...rrowck-move-out-of-overloaded-deref.stderr | 2 +- ...7-reject-move-out-of-borrow-via-pat.stderr | 2 +- src/test/ui/issues/issue-20801.stderr | 8 ++--- .../ui/nll/cannot-move-block-spans.stderr | 12 +++---- src/test/ui/nll/move-errors.stderr | 10 +++--- src/test/ui/std-uncopyable-atomics.stderr | 8 ++--- .../ui/suggestions/dont-suggest-ref/simple.rs | 22 ++++++------- .../dont-suggest-ref/simple.stderr | 22 ++++++------- 13 files changed, 53 insertions(+), 73 deletions(-) diff --git a/src/librustc_mir/borrow_check/move_errors.rs b/src/librustc_mir/borrow_check/move_errors.rs index f892c1597057b..c421839513c01 100644 --- a/src/librustc_mir/borrow_check/move_errors.rs +++ b/src/librustc_mir/borrow_check/move_errors.rs @@ -503,32 +503,12 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> { move_from, .. } => { - let try_remove_deref = match move_from { - Place::Projection(box Projection { - elem: ProjectionElem::Deref, - .. - }) => true, - _ => false, - }; - if try_remove_deref && snippet.starts_with('*') { - // The snippet doesn't start with `*` in (e.g.) index - // expressions `a[b]`, which roughly desugar to - // `*Index::index(&a, b)` or - // `*IndexMut::index_mut(&mut a, b)`. - err.span_suggestion( - span, - "consider removing the `*`", - snippet[1..].to_owned(), - Applicability::Unspecified, - ); - } else { - err.span_suggestion( - span, - "consider borrowing here", - format!("&{}", snippet), - Applicability::Unspecified, - ); - } + err.span_suggestion( + span, + "consider borrowing here", + format!("&{}", snippet), + Applicability::Unspecified, + ); if binds_to.is_empty() { let place_ty = move_from.ty(self.mir, self.infcx.tcx).ty; diff --git a/src/test/ui/access-mode-in-closures.stderr b/src/test/ui/access-mode-in-closures.stderr index 424d7ebb37444..349e3f4a836a0 100644 --- a/src/test/ui/access-mode-in-closures.stderr +++ b/src/test/ui/access-mode-in-closures.stderr @@ -6,7 +6,7 @@ LL | match *s { S(v) => v } | | | | | data moved here | | move occurs because `v` has type `std::vec::Vec`, which does not implement the `Copy` trait - | help: consider removing the `*`: `s` + | help: consider borrowing here: `&*s` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-issue-2657-2.stderr b/src/test/ui/borrowck/borrowck-issue-2657-2.stderr index 908b2c0ff5ee8..5880a1abb818c 100644 --- a/src/test/ui/borrowck/borrowck-issue-2657-2.stderr +++ b/src/test/ui/borrowck/borrowck-issue-2657-2.stderr @@ -5,7 +5,7 @@ LL | let _b = *y; | ^^ | | | move occurs because `*y` has type `std::boxed::Box`, which does not implement the `Copy` trait - | help: consider removing the `*`: `y` + | help: consider borrowing here: `&*y` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr index 13d3faab6508a..d56b9f562c932 100644 --- a/src/test/ui/borrowck/borrowck-move-error-with-note.stderr +++ b/src/test/ui/borrowck/borrowck-move-error-with-note.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `f.0` which is behind a shared reference --> $DIR/borrowck-move-error-with-note.rs:11:11 | LL | match *f { - | ^^ help: consider removing the `*`: `f` + | ^^ help: consider borrowing here: `&*f` LL | Foo::Foo1(num1, | ---- data moved here LL | num2) => (), diff --git a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr index 6c806e0896b37..7dfae33920e1c 100644 --- a/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr +++ b/src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr @@ -5,7 +5,7 @@ LL | let y = *x; | ^^ | | | move occurs because `*x` has type `std::boxed::Box`, which does not implement the `Copy` trait - | help: consider removing the `*`: `x` + | help: consider borrowing here: `&*x` error: aborting due to previous error diff --git a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr index da3e5c54b75f7..1501644fac758 100644 --- a/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr +++ b/src/test/ui/borrowck/borrowck-move-out-of-overloaded-deref.stderr @@ -5,7 +5,7 @@ LL | let _x = *Rc::new("hi".to_string()); | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | | | move occurs because value has type `std::string::String`, which does not implement the `Copy` trait - | help: consider removing the `*`: `Rc::new("hi".to_string())` + | help: consider borrowing here: `&*Rc::new("hi".to_string())` error: aborting due to previous error diff --git a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr index 6ba801b9714bf..78d44f3206199 100644 --- a/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr +++ b/src/test/ui/borrowck/issue-54597-reject-move-out-of-borrow-via-pat.stderr @@ -5,7 +5,7 @@ LL | *array | ^^^^^^ | | | move occurs because `*array` has type `std::vec::Vec`, which does not implement the `Copy` trait - | help: consider removing the `*`: `array` + | help: consider borrowing here: `&*array` error: aborting due to previous error diff --git a/src/test/ui/issues/issue-20801.stderr b/src/test/ui/issues/issue-20801.stderr index 1bbd874a44802..d276231dc0c96 100644 --- a/src/test/ui/issues/issue-20801.stderr +++ b/src/test/ui/issues/issue-20801.stderr @@ -5,7 +5,7 @@ LL | let a = unsafe { *mut_ref() }; | ^^^^^^^^^^ | | | move occurs because value has type `T`, which does not implement the `Copy` trait - | help: consider removing the `*`: `mut_ref()` + | help: consider borrowing here: `&*mut_ref()` error[E0507]: cannot move out of a shared reference --> $DIR/issue-20801.rs:29:22 @@ -14,7 +14,7 @@ LL | let b = unsafe { *imm_ref() }; | ^^^^^^^^^^ | | | move occurs because value has type `T`, which does not implement the `Copy` trait - | help: consider removing the `*`: `imm_ref()` + | help: consider borrowing here: `&*imm_ref()` error[E0507]: cannot move out of a raw pointer --> $DIR/issue-20801.rs:32:22 @@ -23,7 +23,7 @@ LL | let c = unsafe { *mut_ptr() }; | ^^^^^^^^^^ | | | move occurs because value has type `T`, which does not implement the `Copy` trait - | help: consider removing the `*`: `mut_ptr()` + | help: consider borrowing here: `&*mut_ptr()` error[E0507]: cannot move out of a raw pointer --> $DIR/issue-20801.rs:35:22 @@ -32,7 +32,7 @@ LL | let d = unsafe { *const_ptr() }; | ^^^^^^^^^^^^ | | | move occurs because value has type `T`, which does not implement the `Copy` trait - | help: consider removing the `*`: `const_ptr()` + | help: consider borrowing here: `&*const_ptr()` error: aborting due to 4 previous errors diff --git a/src/test/ui/nll/cannot-move-block-spans.stderr b/src/test/ui/nll/cannot-move-block-spans.stderr index 4a9635b060db3..7db5d731acd17 100644 --- a/src/test/ui/nll/cannot-move-block-spans.stderr +++ b/src/test/ui/nll/cannot-move-block-spans.stderr @@ -5,7 +5,7 @@ LL | let x = { *r }; | ^^ | | | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait - | help: consider removing the `*`: `r` + | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:6:22 @@ -14,7 +14,7 @@ LL | let y = unsafe { *r }; | ^^ | | | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait - | help: consider removing the `*`: `r` + | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:7:26 @@ -23,7 +23,7 @@ LL | let z = loop { break *r; }; | ^^ | | | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait - | help: consider removing the `*`: `r` + | help: consider borrowing here: `&*r` error[E0508]: cannot move out of type `[std::string::String; 2]`, a non-copy array --> $DIR/cannot-move-block-spans.rs:11:15 @@ -62,7 +62,7 @@ LL | let x = { let mut u = 0; u += 1; *r }; | ^^ | | | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait - | help: consider removing the `*`: `r` + | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:18:45 @@ -71,7 +71,7 @@ LL | let y = unsafe { let mut u = 0; u += 1; *r }; | ^^ | | | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait - | help: consider removing the `*`: `r` + | help: consider borrowing here: `&*r` error[E0507]: cannot move out of `*r` which is behind a shared reference --> $DIR/cannot-move-block-spans.rs:19:49 @@ -80,7 +80,7 @@ LL | let z = loop { let mut u = 0; u += 1; break *r; u += 2; }; | ^^ | | | move occurs because `*r` has type `std::string::String`, which does not implement the `Copy` trait - | help: consider removing the `*`: `r` + | help: consider borrowing here: `&*r` error: aborting due to 9 previous errors diff --git a/src/test/ui/nll/move-errors.stderr b/src/test/ui/nll/move-errors.stderr index 086f7bcdc4f27..7139617a97a4f 100644 --- a/src/test/ui/nll/move-errors.stderr +++ b/src/test/ui/nll/move-errors.stderr @@ -5,7 +5,7 @@ LL | let b = *a; | ^^ | | | move occurs because `*a` has type `A`, which does not implement the `Copy` trait - | help: consider removing the `*`: `a` + | help: consider borrowing here: `&*a` error[E0508]: cannot move out of type `[A; 1]`, a non-copy array --> $DIR/move-errors.rs:12:13 @@ -24,7 +24,7 @@ LL | let s = **r; | ^^^ | | | move occurs because `**r` has type `A`, which does not implement the `Copy` trait - | help: consider removing the `*`: `*r` + | help: consider borrowing here: `&**r` error[E0507]: cannot move out of an `Rc` --> $DIR/move-errors.rs:27:13 @@ -33,7 +33,7 @@ LL | let s = *r; | ^^ | | | move occurs because value has type `A`, which does not implement the `Copy` trait - | help: consider removing the `*`: `r` + | help: consider borrowing here: `&*r` error[E0508]: cannot move out of type `[A; 1]`, a non-copy array --> $DIR/move-errors.rs:32:13 @@ -49,7 +49,7 @@ error[E0507]: cannot move out of `a.0` which is behind a shared reference --> $DIR/move-errors.rs:38:16 | LL | let A(s) = *a; - | - ^^ help: consider removing the `*`: `a` + | - ^^ help: consider borrowing here: `&*a` | | | data moved here | move occurs because `s` has type `std::string::String`, which does not implement the `Copy` trait @@ -148,7 +148,7 @@ error[E0507]: cannot move out of `x.0` which is behind a shared reference --> $DIR/move-errors.rs:110:11 | LL | match *x { - | ^^ help: consider removing the `*`: `x` + | ^^ help: consider borrowing here: `&*x` LL | LL | Ok(s) | Err(s) => (), | - diff --git a/src/test/ui/std-uncopyable-atomics.stderr b/src/test/ui/std-uncopyable-atomics.stderr index 189a27db382cd..9db9fcf40f82c 100644 --- a/src/test/ui/std-uncopyable-atomics.stderr +++ b/src/test/ui/std-uncopyable-atomics.stderr @@ -5,7 +5,7 @@ LL | let x = *&x; | ^^^ | | | move occurs because value has type `std::sync::atomic::AtomicBool`, which does not implement the `Copy` trait - | help: consider removing the `*`: `&x` + | help: consider borrowing here: `&*&x` error[E0507]: cannot move out of a shared reference --> $DIR/std-uncopyable-atomics.rs:11:13 @@ -14,7 +14,7 @@ LL | let x = *&x; | ^^^ | | | move occurs because value has type `std::sync::atomic::AtomicIsize`, which does not implement the `Copy` trait - | help: consider removing the `*`: `&x` + | help: consider borrowing here: `&*&x` error[E0507]: cannot move out of a shared reference --> $DIR/std-uncopyable-atomics.rs:13:13 @@ -23,7 +23,7 @@ LL | let x = *&x; | ^^^ | | | move occurs because value has type `std::sync::atomic::AtomicUsize`, which does not implement the `Copy` trait - | help: consider removing the `*`: `&x` + | help: consider borrowing here: `&*&x` error[E0507]: cannot move out of a shared reference --> $DIR/std-uncopyable-atomics.rs:15:13 @@ -32,7 +32,7 @@ LL | let x = *&x; | ^^^ | | | move occurs because value has type `std::sync::atomic::AtomicPtr`, which does not implement the `Copy` trait - | help: consider removing the `*`: `&x` + | help: consider borrowing here: `&*&x` error: aborting due to 4 previous errors diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.rs b/src/test/ui/suggestions/dont-suggest-ref/simple.rs index 31ab1a6639acc..69b303a66237e 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/simple.rs +++ b/src/test/ui/suggestions/dont-suggest-ref/simple.rs @@ -37,26 +37,26 @@ pub fn main() { let X(_t) = *s; //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION s if let Either::One(_t) = *r { } //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION r while let Either::One(_t) = *r { } //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION r match *r { //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION r Either::One(_t) | Either::Two(_t) => (), } match *r { //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION r Either::One(_t) => (), Either::Two(ref _t) => (), @@ -65,26 +65,26 @@ pub fn main() { let X(_t) = *sm; //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION sm if let Either::One(_t) = *rm { } //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION rm while let Either::One(_t) = *rm { } //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION rm match *rm { //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION rm Either::One(_t) | Either::Two(_t) => (), } match *rm { //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION rm Either::One(_t) => (), Either::Two(ref _t) => (), @@ -92,7 +92,7 @@ pub fn main() { } match *rm { //~^ ERROR cannot move - //~| HELP consider removing the `*` + //~| HELP consider borrowing here //~| SUGGESTION rm Either::One(_t) => (), Either::Two(ref mut _t) => (), diff --git a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr index bde3afa3840a2..cb3ce5991aeee 100644 --- a/src/test/ui/suggestions/dont-suggest-ref/simple.stderr +++ b/src/test/ui/suggestions/dont-suggest-ref/simple.stderr @@ -2,7 +2,7 @@ error[E0507]: cannot move out of `s.0` which is behind a shared reference --> $DIR/simple.rs:38:17 | LL | let X(_t) = *s; - | -- ^^ help: consider removing the `*`: `s` + | -- ^^ help: consider borrowing here: `&*s` | | | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait @@ -11,7 +11,7 @@ error[E0507]: cannot move out of `r.0` which is behind a shared reference --> $DIR/simple.rs:42:30 | LL | if let Either::One(_t) = *r { } - | -- ^^ help: consider removing the `*`: `r` + | -- ^^ help: consider borrowing here: `&*r` | | | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait @@ -20,7 +20,7 @@ error[E0507]: cannot move out of `r.0` which is behind a shared reference --> $DIR/simple.rs:46:33 | LL | while let Either::One(_t) = *r { } - | -- ^^ help: consider removing the `*`: `r` + | -- ^^ help: consider borrowing here: `&*r` | | | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait @@ -29,7 +29,7 @@ error[E0507]: cannot move out of `r.0` which is behind a shared reference --> $DIR/simple.rs:50:11 | LL | match *r { - | ^^ help: consider removing the `*`: `r` + | ^^ help: consider borrowing here: `&*r` ... LL | Either::One(_t) | -- @@ -41,7 +41,7 @@ error[E0507]: cannot move out of `r.0` which is behind a shared reference --> $DIR/simple.rs:57:11 | LL | match *r { - | ^^ help: consider removing the `*`: `r` + | ^^ help: consider borrowing here: `&*r` ... LL | Either::One(_t) => (), | -- @@ -53,7 +53,7 @@ error[E0507]: cannot move out of `sm.0` which is behind a mutable reference --> $DIR/simple.rs:66:17 | LL | let X(_t) = *sm; - | -- ^^^ help: consider removing the `*`: `sm` + | -- ^^^ help: consider borrowing here: `&*sm` | | | data moved here | move occurs because `_t` has type `Y`, which does not implement the `Copy` trait @@ -62,7 +62,7 @@ error[E0507]: cannot move out of `rm.0` which is behind a mutable reference --> $DIR/simple.rs:70:30 | LL | if let Either::One(_t) = *rm { } - | -- ^^^ help: consider removing the `*`: `rm` + | -- ^^^ help: consider borrowing here: `&*rm` | | | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait @@ -71,7 +71,7 @@ error[E0507]: cannot move out of `rm.0` which is behind a mutable reference --> $DIR/simple.rs:74:33 | LL | while let Either::One(_t) = *rm { } - | -- ^^^ help: consider removing the `*`: `rm` + | -- ^^^ help: consider borrowing here: `&*rm` | | | data moved here | move occurs because `_t` has type `X`, which does not implement the `Copy` trait @@ -80,7 +80,7 @@ error[E0507]: cannot move out of `rm.0` which is behind a mutable reference --> $DIR/simple.rs:78:11 | LL | match *rm { - | ^^^ help: consider removing the `*`: `rm` + | ^^^ help: consider borrowing here: `&*rm` ... LL | Either::One(_t) | -- @@ -92,7 +92,7 @@ error[E0507]: cannot move out of `rm.0` which is behind a mutable reference --> $DIR/simple.rs:85:11 | LL | match *rm { - | ^^^ help: consider removing the `*`: `rm` + | ^^^ help: consider borrowing here: `&*rm` ... LL | Either::One(_t) => (), | -- @@ -104,7 +104,7 @@ error[E0507]: cannot move out of `rm.0` which is behind a mutable reference --> $DIR/simple.rs:93:11 | LL | match *rm { - | ^^^ help: consider removing the `*`: `rm` + | ^^^ help: consider borrowing here: `&*rm` ... LL | Either::One(_t) => (), | -- From 529b94ea6a3f0606d38e4bb32ec5eb692c3c0d71 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Tue, 4 Jun 2019 21:51:30 -0400 Subject: [PATCH 02/12] [const-prop] Fix ICE when casting function pointers This fixes an ICE when building libcore with `-Z mir-opt-level=3`. --- src/librustc_mir/transform/const_prop.rs | 10 ++++----- src/test/mir-opt/const_prop/reify_fn_ptr.rs | 25 +++++++++++++++++++++ 2 files changed, 29 insertions(+), 6 deletions(-) create mode 100644 src/test/mir-opt/const_prop/reify_fn_ptr.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index dbaa4e557c66f..1d4d01e60aad0 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -525,12 +525,10 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { source_info: SourceInfo, ) { trace!("attepting to replace {:?} with {:?}", rval, value); - self.ecx.validate_operand( - value, - vec![], - None, - true, - ).expect("value should already be a valid const"); + if let Err(e) = self.ecx.validate_operand(value, vec![], None, true) { + trace!("validation error, attempt failed: {:?}", e); + return; + } // FIXME> figure out what tho do when try_read_immediate fails let imm = self.use_ecx(source_info, |this| { diff --git a/src/test/mir-opt/const_prop/reify_fn_ptr.rs b/src/test/mir-opt/const_prop/reify_fn_ptr.rs new file mode 100644 index 0000000000000..809eb19ade899 --- /dev/null +++ b/src/test/mir-opt/const_prop/reify_fn_ptr.rs @@ -0,0 +1,25 @@ +fn main() { + let _ = main as usize as *const fn(); +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _3 = const main as fn() (Pointer(ReifyFnPointer)); +// _2 = move _3 as usize (Misc); +// ... +// _1 = move _2 as *const fn() (Misc); +// ... +// } +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _3 = const Scalar(AllocId(1).0x0) : fn(); +// _2 = move _3 as usize (Misc); +// ... +// _1 = const Scalar(AllocId(1).0x0) : *const fn(); +// ... +// } +// END rustc.main.ConstProp.after.mir From 9f4d94b908d333161442c77314e1527eb8223a0e Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Fri, 31 May 2019 04:35:57 -0400 Subject: [PATCH 03/12] [const-prop] Handle Rvalue::Ref --- src/librustc_mir/interpret/place.rs | 17 +++++++++++++++++ src/librustc_mir/transform/const_prop.rs | 6 +++++- 2 files changed, 22 insertions(+), 1 deletion(-) diff --git a/src/librustc_mir/interpret/place.rs b/src/librustc_mir/interpret/place.rs index fac9665d968e2..a3297666113d4 100644 --- a/src/librustc_mir/interpret/place.rs +++ b/src/librustc_mir/interpret/place.rs @@ -663,6 +663,23 @@ where Ok(()) } + /// Write an `Immediate` to memory. + #[inline(always)] + pub fn write_immediate_to_mplace( + &mut self, + src: Immediate, + dest: MPlaceTy<'tcx, M::PointerTag>, + ) -> EvalResult<'tcx> { + self.write_immediate_to_mplace_no_validate(src, dest)?; + + if M::enforce_validity(self) { + // Data got changed, better make sure it matches the type! + self.validate_operand(dest.into(), vec![], None, /*const_mode*/ false)?; + } + + Ok(()) + } + /// Write an immediate to a place. /// If you use this you are responsible for validating that things got copied at the /// right type. diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 1d4d01e60aad0..8e7093b833d44 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -363,8 +363,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { Rvalue::Use(ref op) => { self.eval_operand(op, source_info) }, + Rvalue::Ref(_, _, ref place) => { + let src = self.eval_place(place, source_info)?; + let mplace = src.try_as_mplace().ok()?; + Some(ImmTy::from_scalar(mplace.ptr.into(), place_layout).into()) + }, Rvalue::Repeat(..) | - Rvalue::Ref(..) | Rvalue::Aggregate(..) | Rvalue::NullaryOp(NullOp::Box, _) | Rvalue::Discriminant(..) => None, From 1e50e01bb7c3200c48c8739435d4e7cece83ed6c Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 3 Jun 2019 21:52:26 -0400 Subject: [PATCH 04/12] [const-prop] Handle ProjectionElem::Deref --- src/librustc_mir/transform/const_prop.rs | 6 ++++++ src/test/mir-opt/const_prop/ref_deref.rs | 21 +++++++++++++++++++++ 2 files changed, 27 insertions(+) create mode 100644 src/test/mir-opt/const_prop/ref_deref.rs diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 8e7093b833d44..693fc9ba2f327 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -333,6 +333,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { this.ecx.operand_field(eval, field.index() as u64) })?; }, + ProjectionElem::Deref => { + trace!("processing deref"); + eval = self.use_ecx(source_info, |this| { + this.ecx.deref_operand(eval) + })?.into(); + } // We could get more projections by using e.g., `operand_projection`, // but we do not even have the stack frame set up properly so // an `Index` projection would throw us off-track. diff --git a/src/test/mir-opt/const_prop/ref_deref.rs b/src/test/mir-opt/const_prop/ref_deref.rs new file mode 100644 index 0000000000000..2d04822c0e789 --- /dev/null +++ b/src/test/mir-opt/const_prop/ref_deref.rs @@ -0,0 +1,21 @@ +fn main() { + *(&4); +} + +// END RUST SOURCE +// START rustc.main.ConstProp.before.mir +// bb0: { +// ... +// _2 = &(promoted[0]: i32); +// _1 = (*_2); +// ... +//} +// END rustc.main.ConstProp.before.mir +// START rustc.main.ConstProp.after.mir +// bb0: { +// ... +// _2 = const Scalar(AllocId(0).0x0) : &i32; +// _1 = const 4i32; +// ... +// } +// END rustc.main.ConstProp.after.mir From dee05ab2cca6d6d19cc73c6f900eee32e2dd5cbd Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Mon, 20 May 2019 05:46:33 -0400 Subject: [PATCH 05/12] [const-prop] Handle Rvalue::Len --- src/librustc_mir/transform/const_prop.rs | 29 ++++++++++++++--- src/test/mir-opt/const_prop/slice_len.rs | 40 +++++++++++++----------- 2 files changed, 46 insertions(+), 23 deletions(-) diff --git a/src/librustc_mir/transform/const_prop.rs b/src/librustc_mir/transform/const_prop.rs index 693fc9ba2f327..0d389b31f9075 100644 --- a/src/librustc_mir/transform/const_prop.rs +++ b/src/librustc_mir/transform/const_prop.rs @@ -17,8 +17,7 @@ use syntax_pos::{Span, DUMMY_SP}; use rustc::ty::subst::InternalSubsts; use rustc_data_structures::indexed_vec::IndexVec; use rustc::ty::layout::{ - LayoutOf, TyLayout, LayoutError, - HasTyCtxt, TargetDataLayout, HasDataLayout, + LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, Size, }; use crate::interpret::{ @@ -386,10 +385,30 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> { this.ecx.cast(op, kind, dest.into())?; Ok(dest.into()) }) - } + }, + Rvalue::Len(ref place) => { + let place = self.eval_place(&place, source_info)?; + let mplace = place.try_as_mplace().ok()?; + + if let ty::Slice(_) = mplace.layout.ty.sty { + let len = mplace.meta.unwrap().to_usize(&self.ecx).unwrap(); - // FIXME(oli-obk): evaluate static/constant slice lengths - Rvalue::Len(_) => None, + Some(ImmTy { + imm: Immediate::Scalar( + Scalar::from_uint( + len, + Size::from_bits( + self.tcx.sess.target.usize_ty.bit_width().unwrap() as u64 + ) + ).into(), + ), + layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?, + }.into()) + } else { + trace!("not slice: {:?}", mplace.layout.ty.sty); + None + } + }, Rvalue::NullaryOp(NullOp::SizeOf, ty) => { type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some( ImmTy { diff --git a/src/test/mir-opt/const_prop/slice_len.rs b/src/test/mir-opt/const_prop/slice_len.rs index 3435ca07f4cd8..5babeb195a826 100644 --- a/src/test/mir-opt/const_prop/slice_len.rs +++ b/src/test/mir-opt/const_prop/slice_len.rs @@ -1,22 +1,22 @@ -fn test() -> &'static [u32] { - &[1, 2] -} - fn main() { - let x = test()[0]; + (&[1u32, 2, 3] as &[u32])[1]; } // END RUST SOURCE // START rustc.main.ConstProp.before.mir -// bb1: { +// bb0: { // ... -// _3 = const 0usize; -// _4 = Len((*_2)); -// _5 = Lt(_3, _4); -// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2; +// _4 = &(promoted[0]: [u32; 3]); +// _3 = _4; +// _2 = move _3 as &[u32] (Pointer(Unsize)); +// ... +// _6 = const 1usize; +// _7 = Len((*_2)); +// _8 = Lt(_6, _7); +// assert(move _8, "index out of bounds: the len is move _7 but the index is _6") -> bb1; // } -// bb2: { -// _1 = (*_2)[_3]; +// bb1: { +// _1 = (*_2)[_6]; // ... // return; // } @@ -24,13 +24,17 @@ fn main() { // START rustc.main.ConstProp.after.mir // bb0: { // ... -// _3 = const 0usize; -// _4 = Len((*_2)); -// _5 = Lt(_3, _4); -// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2; +// _4 = const Scalar(AllocId(0).0x0) : &[u32; 3]; +// _3 = const Scalar(AllocId(0).0x0) : &[u32; 3]; +// _2 = move _3 as &[u32] (Pointer(Unsize)); +// ... +// _6 = const 1usize; +// _7 = const 3usize; +// _8 = const true; +// assert(const true, "index out of bounds: the len is move _7 but the index is _6") -> bb1; // } -// bb2: { -// _1 = (*_2)[_3]; +// bb1: { +// _1 = (*_2)[_6]; // ... // return; // } From 7d1f762c80e684acf7228fb1b37681ecc6c1110c Mon Sep 17 00:00:00 2001 From: Alex Crichton Date: Thu, 6 Jun 2019 07:57:37 -0700 Subject: [PATCH 06/12] ci: Disable LLVM/debug assertions for asmjs builder This shaves of 50 minutes of cycle time on Azure and will likely also save a significant chunk of time on Travis. The assertions here aren't really buying us much over other builders with assertions already enabled, so let's disable them for this builder. cc #61185 --- src/ci/docker/asmjs/Dockerfile | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/src/ci/docker/asmjs/Dockerfile b/src/ci/docker/asmjs/Dockerfile index 9eaffbf83eb4e..01d6fce34186a 100644 --- a/src/ci/docker/asmjs/Dockerfile +++ b/src/ci/docker/asmjs/Dockerfile @@ -37,3 +37,11 @@ ENV SCRIPT python2.7 ../x.py test --target $TARGETS \ src/libstd \ src/liballoc \ src/libcore + +# Debug assertions in rustc are largely covered by other builders, and LLVM +# assertions cause this builder to slow down by quite a large amount and don't +# buy us a huge amount over other builders (not sure if we've ever seen an +# asmjs-specific backend assertion trip), so disable assertions for these +# tests. +ENV NO_LLVM_ASSERTIONS=1 +ENV NO_DEBUG_ASSERTIONS=1 From 9a498419615600741d6c29fb3ace4e31a1831efa Mon Sep 17 00:00:00 2001 From: Dario Gonzalez Date: Thu, 6 Jun 2019 14:06:49 -0700 Subject: [PATCH 07/12] increase max heapsize available during sgx tests --- src/libstd/Cargo.toml | 2 ++ 1 file changed, 2 insertions(+) diff --git a/src/libstd/Cargo.toml b/src/libstd/Cargo.toml index 816a191a2a930..1ef360a8e3279 100644 --- a/src/libstd/Cargo.toml +++ b/src/libstd/Cargo.toml @@ -87,3 +87,5 @@ std_detect_dlsym_getauxval = [] [package.metadata.fortanix-sgx] # Maximum possible number of threads when testing threads = 125 +# Maximum heap size +heap_size = 0x8000000 From 459e37b304f62659b59215eed57da991873b3445 Mon Sep 17 00:00:00 2001 From: Wesley Wiser Date: Thu, 6 Jun 2019 17:52:17 -0400 Subject: [PATCH 08/12] Bless test output --- src/test/ui/consts/const-eval/promoted_errors.stderr | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/src/test/ui/consts/const-eval/promoted_errors.stderr b/src/test/ui/consts/const-eval/promoted_errors.stderr index c9d5ede61ade4..c9f3a7659f9cd 100644 --- a/src/test/ui/consts/const-eval/promoted_errors.stderr +++ b/src/test/ui/consts/const-eval/promoted_errors.stderr @@ -16,6 +16,12 @@ warning: attempt to divide by zero LL | println!("{}", 1/(1-1)); | ^^^^^^^ +warning: this expression will panic at runtime + --> $DIR/promoted_errors.rs:9:20 + | +LL | println!("{}", 1/(1-1)); + | ^^^^^^^ attempt to divide by zero + warning: attempt to divide by zero --> $DIR/promoted_errors.rs:11:14 | @@ -34,6 +40,12 @@ warning: attempt to divide by zero LL | println!("{}", 1/(false as u32)); | ^^^^^^^^^^^^^^^^ +warning: this expression will panic at runtime + --> $DIR/promoted_errors.rs:14:20 + | +LL | println!("{}", 1/(false as u32)); + | ^^^^^^^^^^^^^^^^ attempt to divide by zero + warning: attempt to divide by zero --> $DIR/promoted_errors.rs:16:14 | From fb61b851efd7da06e72b193174305ab37abbf609 Mon Sep 17 00:00:00 2001 From: Thomas Bracht Laumann Jespersen Date: Thu, 6 Jun 2019 21:42:15 +0200 Subject: [PATCH 09/12] libcore/pin: Minor grammar corrections for module documentation This is by no means exhaustive, but I noticed a few grammatical errors when reading the documentation, and decided just to push these. Some standard rules/guidelines I followed: * Do not split infinitives, ie "not to move" instead of "to not move" * Do not use "since" when you want to say "because" or "as" - the word "since" has a temporal meaning In addition: * Fix a small typo: "Similarily" should be "Similarly" * Delete double-spaces after full stop --- src/libcore/pin.rs | 41 +++++++++++++++++++++-------------------- 1 file changed, 21 insertions(+), 20 deletions(-) diff --git a/src/libcore/pin.rs b/src/libcore/pin.rs index 4ced860948bee..c5247e134c86a 100644 --- a/src/libcore/pin.rs +++ b/src/libcore/pin.rs @@ -1,10 +1,10 @@ //! Types that pin data to its location in memory. //! -//! It is sometimes useful to have objects that are guaranteed to not move, +//! It is sometimes useful to have objects that are guaranteed not to move, //! in the sense that their placement in memory does not change, and can thus be relied upon. //! A prime example of such a scenario would be building self-referential structs, -//! since moving an object with pointers to itself will invalidate them, -//! which could cause undefined behavior. +//! as moving an object with pointers to itself will invalidate them, which could cause undefined +//! behavior. //! //! A [`Pin

`] ensures that the pointee of any pointer type `P` has a stable location in memory, //! meaning it cannot be moved elsewhere and its memory cannot be deallocated @@ -15,9 +15,10 @@ //! moving the values they contain: you can move out of a `Box`, or you can use [`mem::swap`]. //! [`Pin

`] wraps a pointer type `P`, so `Pin>` functions much like a regular `Box`: //! when a `Pin>` gets dropped, so do its contents, and the memory gets deallocated. -//! Similarily, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin

`] does not let clients +//! Similarly, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin

`] does not let clients //! actually obtain a `Box` or `&mut T` to pinned data, which implies that you cannot use //! operations such as [`mem::swap`]: +//! //! ``` //! use std::pin::Pin; //! fn swap_pins(x: Pin<&mut T>, y: Pin<&mut T>) { @@ -39,19 +40,19 @@ //! as a "`P`-style pointer" to a pinned `P::Target` -- so, a `Pin>` is //! an owned pointer to a pinned `T`, and a `Pin>` is a reference-counted //! pointer to a pinned `T`. -//! For correctness, [`Pin

`] relies on the [`Deref`] and [`DerefMut`] implementations -//! to not move out of their `self` parameter, and to only ever return a pointer -//! to pinned data when they are called on a pinned pointer. +//! For correctness, [`Pin

`] relies on the implementations of [`Deref`] and +//! [`DerefMut`] not to move out of their `self` parameter, and only ever to +//! return a pointer to pinned data when they are called on a pinned pointer. //! //! # `Unpin` //! -//! However, these restrictions are usually not necessary. Many types are always freely -//! movable, even when pinned, because they do not rely on having a stable address. -//! This includes all the basic types (like `bool`, `i32`, references) -//! as well as types consisting solely of these types. -//! Types that do not care about pinning implement the [`Unpin`] auto-trait, which -//! cancels the effect of [`Pin

`]. For `T: Unpin`, `Pin>` and `Box` function -//! identically, as do `Pin<&mut T>` and `&mut T`. +//! Many types are always freely movable, even when pinned, because they do not +//! rely on having a stable address. This includes all the basic types (like +//! `bool`, `i32`, and references) as well as types consisting solely of these +//! types. Types that do not care about pinning implement the [`Unpin`] +//! auto-trait, which cancels the effect of [`Pin

`]. For `T: Unpin`, +//! `Pin>` and `Box` function identically, as do `Pin<&mut T>` and +//! `&mut T`. //! //! Note that pinning and `Unpin` only affect the pointed-to type `P::Target`, not the pointer //! type `P` itself that got wrapped in `Pin

`. For example, whether or not `Box` is @@ -65,11 +66,11 @@ //! use std::marker::PhantomPinned; //! use std::ptr::NonNull; //! -//! // This is a self-referential struct since the slice field points to the data field. +//! // This is a self-referential struct because the slice field points to the data field. //! // We cannot inform the compiler about that with a normal reference, -//! // since this pattern cannot be described with the usual borrowing rules. -//! // Instead we use a raw pointer, though one which is known to not be null, -//! // since we know it's pointing at the string. +//! // as this pattern cannot be described with the usual borrowing rules. +//! // Instead we use a raw pointer, though one which is known not to be null, +//! // as we know it's pointing at the string. //! struct Unmovable { //! data: String, //! slice: NonNull, @@ -146,7 +147,7 @@ //! section needs to function correctly. //! //! Notice that this guarantee does *not* mean that memory does not leak! It is still -//! completely okay not to ever call `drop` on a pinned element (e.g., you can still +//! completely okay not ever to call `drop` on a pinned element (e.g., you can still //! call [`mem::forget`] on a `Pin>`). In the example of the doubly-linked //! list, that element would just stay in the list. However you may not free or reuse the storage //! *without calling `drop`*. @@ -192,7 +193,7 @@ //! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of //! the wrapper it is your responsibility *not* to add something like //! `impl Unpin for Wrapper`. (Notice that adding a projection operation -//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break +//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break //! the principle that you only have to worry about any of this if you use `unsafe`.) //! 2. The destructor of the wrapper must not move structural fields out of its argument. This //! is the exact point that was raised in the [previous section][drop-impl]: `drop` takes From 625763fddd4281200f0f244a601f659fa1782de5 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Jun 2019 13:48:38 +0200 Subject: [PATCH 10/12] make the backtrace field of EvalError private This also makes sure people don't contruct these the wrong way --- src/librustc/mir/interpret/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index b4615aeb0db15..83204dcf62bac 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -182,7 +182,7 @@ pub fn struct_error<'a, 'gcx, 'tcx>( #[derive(Debug, Clone)] pub struct EvalError<'tcx> { pub kind: InterpError<'tcx, u64>, - pub backtrace: Option>, + backtrace: Option>, } impl<'tcx> EvalError<'tcx> { From 524f1463cd6b0025d77f34e6911bce6e37c3e8ea Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Fri, 7 Jun 2019 15:51:29 +0200 Subject: [PATCH 11/12] add doc comment for EvalError --- src/librustc/mir/interpret/error.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/librustc/mir/interpret/error.rs b/src/librustc/mir/interpret/error.rs index 83204dcf62bac..e324abd8e2f32 100644 --- a/src/librustc/mir/interpret/error.rs +++ b/src/librustc/mir/interpret/error.rs @@ -179,6 +179,11 @@ pub fn struct_error<'a, 'gcx, 'tcx>( struct_span_err!(tcx.sess, tcx.span, E0080, "{}", msg) } +/// Packages the kind of error we got from the const code interpreter +/// up with a Rust-level backtrace of where the error occured. +/// Thsese should always be constructed by calling `.into()` on +/// a `InterpError`. In `librustc_mir::interpret`, we have the `err!` +/// macro for this #[derive(Debug, Clone)] pub struct EvalError<'tcx> { pub kind: InterpError<'tcx, u64>, From 8f3753703c9e4e587fcb9790a07aa18b310b8431 Mon Sep 17 00:00:00 2001 From: Guillaume Gomez Date: Fri, 7 Jun 2019 00:58:32 +0200 Subject: [PATCH 12/12] Fix slice const generic length display --- src/librustdoc/clean/mod.rs | 5 ++++- .../rustdoc/const-generics/const-generic-slice.rs | 12 ++++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) create mode 100644 src/test/rustdoc/const-generics/const-generic-slice.rs diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 03d16feb483a9..a717ef20a8444 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -2768,7 +2768,10 @@ impl Clean for hir::Ty { }; let length = match cx.tcx.const_eval(param_env.and(cid)) { Ok(length) => print_const(cx, length), - Err(_) => "_".to_string(), + Err(_) => cx.sess() + .source_map() + .span_to_snippet(cx.tcx.def_span(def_id)) + .unwrap_or_else(|_| "_".to_string()), }; Array(box ty.clean(cx), length) }, diff --git a/src/test/rustdoc/const-generics/const-generic-slice.rs b/src/test/rustdoc/const-generics/const-generic-slice.rs new file mode 100644 index 0000000000000..60d96770f7eae --- /dev/null +++ b/src/test/rustdoc/const-generics/const-generic-slice.rs @@ -0,0 +1,12 @@ +#![crate_name = "foo"] +#![feature(const_generics)] + +pub trait Array { + type Item; +} + +// @has foo/trait.Array.html +// @has - '//h3[@class="impl"]' 'impl Array for [T; N]' +impl Array for [T; N] { + type Item = T; +}