Skip to content

Commit 746f0dc

Browse files
committed
Auto merge of #61619 - Centril:rollup-b8hmiw7, r=Centril
Rollup of 4 pull requests Successful merges: - #61332 (Remove asterisk suggestion for move errors in borrowck) - #61532 ([const-prop] Support Rvalue::{Ref,Len} and Deref) - #61586 (ci: Disable LLVM/debug assertions for asmjs builder) - #61599 (libcore/pin: Minor grammar corrections for module documentation) Failed merges: r? @ghost
2 parents c1c60d2 + 838002d commit 746f0dc

21 files changed

+218
-123
lines changed

src/ci/docker/asmjs/Dockerfile

+8
Original file line numberDiff line numberDiff line change
@@ -37,3 +37,11 @@ ENV SCRIPT python2.7 ../x.py test --target $TARGETS \
3737
src/libstd \
3838
src/liballoc \
3939
src/libcore
40+
41+
# Debug assertions in rustc are largely covered by other builders, and LLVM
42+
# assertions cause this builder to slow down by quite a large amount and don't
43+
# buy us a huge amount over other builders (not sure if we've ever seen an
44+
# asmjs-specific backend assertion trip), so disable assertions for these
45+
# tests.
46+
ENV NO_LLVM_ASSERTIONS=1
47+
ENV NO_DEBUG_ASSERTIONS=1

src/libcore/pin.rs

+21-20
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
//! Types that pin data to its location in memory.
22
//!
3-
//! It is sometimes useful to have objects that are guaranteed to not move,
3+
//! It is sometimes useful to have objects that are guaranteed not to move,
44
//! in the sense that their placement in memory does not change, and can thus be relied upon.
55
//! A prime example of such a scenario would be building self-referential structs,
6-
//! since moving an object with pointers to itself will invalidate them,
7-
//! which could cause undefined behavior.
6+
//! as moving an object with pointers to itself will invalidate them, which could cause undefined
7+
//! behavior.
88
//!
99
//! A [`Pin<P>`] ensures that the pointee of any pointer type `P` has a stable location in memory,
1010
//! meaning it cannot be moved elsewhere and its memory cannot be deallocated
@@ -15,9 +15,10 @@
1515
//! moving the values they contain: you can move out of a `Box<T>`, or you can use [`mem::swap`].
1616
//! [`Pin<P>`] wraps a pointer type `P`, so `Pin<Box<T>>` functions much like a regular `Box<T>`:
1717
//! when a `Pin<Box<T>>` gets dropped, so do its contents, and the memory gets deallocated.
18-
//! Similarily, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin<P>`] does not let clients
18+
//! Similarly, `Pin<&mut T>` is a lot like `&mut T`. However, [`Pin<P>`] does not let clients
1919
//! actually obtain a `Box<T>` or `&mut T` to pinned data, which implies that you cannot use
2020
//! operations such as [`mem::swap`]:
21+
//!
2122
//! ```
2223
//! use std::pin::Pin;
2324
//! fn swap_pins<T>(x: Pin<&mut T>, y: Pin<&mut T>) {
@@ -39,19 +40,19 @@
3940
//! as a "`P`-style pointer" to a pinned `P::Target` -- so, a `Pin<Box<T>>` is
4041
//! an owned pointer to a pinned `T`, and a `Pin<Rc<T>>` is a reference-counted
4142
//! pointer to a pinned `T`.
42-
//! For correctness, [`Pin<P>`] relies on the [`Deref`] and [`DerefMut`] implementations
43-
//! to not move out of their `self` parameter, and to only ever return a pointer
44-
//! to pinned data when they are called on a pinned pointer.
43+
//! For correctness, [`Pin<P>`] relies on the implementations of [`Deref`] and
44+
//! [`DerefMut`] not to move out of their `self` parameter, and only ever to
45+
//! return a pointer to pinned data when they are called on a pinned pointer.
4546
//!
4647
//! # `Unpin`
4748
//!
48-
//! However, these restrictions are usually not necessary. Many types are always freely
49-
//! movable, even when pinned, because they do not rely on having a stable address.
50-
//! This includes all the basic types (like `bool`, `i32`, references)
51-
//! as well as types consisting solely of these types.
52-
//! Types that do not care about pinning implement the [`Unpin`] auto-trait, which
53-
//! cancels the effect of [`Pin<P>`]. For `T: Unpin`, `Pin<Box<T>>` and `Box<T>` function
54-
//! identically, as do `Pin<&mut T>` and `&mut T`.
49+
//! Many types are always freely movable, even when pinned, because they do not
50+
//! rely on having a stable address. This includes all the basic types (like
51+
//! `bool`, `i32`, and references) as well as types consisting solely of these
52+
//! types. Types that do not care about pinning implement the [`Unpin`]
53+
//! auto-trait, which cancels the effect of [`Pin<P>`]. For `T: Unpin`,
54+
//! `Pin<Box<T>>` and `Box<T>` function identically, as do `Pin<&mut T>` and
55+
//! `&mut T`.
5556
//!
5657
//! Note that pinning and `Unpin` only affect the pointed-to type `P::Target`, not the pointer
5758
//! type `P` itself that got wrapped in `Pin<P>`. For example, whether or not `Box<T>` is
@@ -65,11 +66,11 @@
6566
//! use std::marker::PhantomPinned;
6667
//! use std::ptr::NonNull;
6768
//!
68-
//! // This is a self-referential struct since the slice field points to the data field.
69+
//! // This is a self-referential struct because the slice field points to the data field.
6970
//! // We cannot inform the compiler about that with a normal reference,
70-
//! // since this pattern cannot be described with the usual borrowing rules.
71-
//! // Instead we use a raw pointer, though one which is known to not be null,
72-
//! // since we know it's pointing at the string.
71+
//! // as this pattern cannot be described with the usual borrowing rules.
72+
//! // Instead we use a raw pointer, though one which is known not to be null,
73+
//! // as we know it's pointing at the string.
7374
//! struct Unmovable {
7475
//! data: String,
7576
//! slice: NonNull<String>,
@@ -146,7 +147,7 @@
146147
//! section needs to function correctly.
147148
//!
148149
//! Notice that this guarantee does *not* mean that memory does not leak! It is still
149-
//! completely okay not to ever call `drop` on a pinned element (e.g., you can still
150+
//! completely okay not ever to call `drop` on a pinned element (e.g., you can still
150151
//! call [`mem::forget`] on a `Pin<Box<T>>`). In the example of the doubly-linked
151152
//! list, that element would just stay in the list. However you may not free or reuse the storage
152153
//! *without calling `drop`*.
@@ -192,7 +193,7 @@
192193
//! `Unpin`. This is the default, but `Unpin` is a safe trait, so as the author of
193194
//! the wrapper it is your responsibility *not* to add something like
194195
//! `impl<T> Unpin for Wrapper<T>`. (Notice that adding a projection operation
195-
//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break
196+
//! requires unsafe code, so the fact that `Unpin` is a safe trait does not break
196197
//! the principle that you only have to worry about any of this if you use `unsafe`.)
197198
//! 2. The destructor of the wrapper must not move structural fields out of its argument. This
198199
//! is the exact point that was raised in the [previous section][drop-impl]: `drop` takes

src/librustc_mir/borrow_check/move_errors.rs

+6-26
Original file line numberDiff line numberDiff line change
@@ -503,32 +503,12 @@ impl<'a, 'gcx, 'tcx> MirBorrowckCtxt<'a, 'gcx, 'tcx> {
503503
move_from,
504504
..
505505
} => {
506-
let try_remove_deref = match move_from {
507-
Place::Projection(box Projection {
508-
elem: ProjectionElem::Deref,
509-
..
510-
}) => true,
511-
_ => false,
512-
};
513-
if try_remove_deref && snippet.starts_with('*') {
514-
// The snippet doesn't start with `*` in (e.g.) index
515-
// expressions `a[b]`, which roughly desugar to
516-
// `*Index::index(&a, b)` or
517-
// `*IndexMut::index_mut(&mut a, b)`.
518-
err.span_suggestion(
519-
span,
520-
"consider removing the `*`",
521-
snippet[1..].to_owned(),
522-
Applicability::Unspecified,
523-
);
524-
} else {
525-
err.span_suggestion(
526-
span,
527-
"consider borrowing here",
528-
format!("&{}", snippet),
529-
Applicability::Unspecified,
530-
);
531-
}
506+
err.span_suggestion(
507+
span,
508+
"consider borrowing here",
509+
format!("&{}", snippet),
510+
Applicability::Unspecified,
511+
);
532512

533513
if binds_to.is_empty() {
534514
let place_ty = move_from.ty(self.mir, self.infcx.tcx).ty;

src/librustc_mir/interpret/place.rs

+17
Original file line numberDiff line numberDiff line change
@@ -663,6 +663,23 @@ where
663663
Ok(())
664664
}
665665

666+
/// Write an `Immediate` to memory.
667+
#[inline(always)]
668+
pub fn write_immediate_to_mplace(
669+
&mut self,
670+
src: Immediate<M::PointerTag>,
671+
dest: MPlaceTy<'tcx, M::PointerTag>,
672+
) -> EvalResult<'tcx> {
673+
self.write_immediate_to_mplace_no_validate(src, dest)?;
674+
675+
if M::enforce_validity(self) {
676+
// Data got changed, better make sure it matches the type!
677+
self.validate_operand(dest.into(), vec![], None, /*const_mode*/ false)?;
678+
}
679+
680+
Ok(())
681+
}
682+
666683
/// Write an immediate to a place.
667684
/// If you use this you are responsible for validating that things got copied at the
668685
/// right type.

src/librustc_mir/transform/const_prop.rs

+39-12
Original file line numberDiff line numberDiff line change
@@ -17,8 +17,7 @@ use syntax_pos::{Span, DUMMY_SP};
1717
use rustc::ty::subst::InternalSubsts;
1818
use rustc_data_structures::indexed_vec::IndexVec;
1919
use rustc::ty::layout::{
20-
LayoutOf, TyLayout, LayoutError,
21-
HasTyCtxt, TargetDataLayout, HasDataLayout,
20+
LayoutOf, TyLayout, LayoutError, HasTyCtxt, TargetDataLayout, HasDataLayout, Size,
2221
};
2322

2423
use crate::interpret::{
@@ -333,6 +332,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
333332
this.ecx.operand_field(eval, field.index() as u64)
334333
})?;
335334
},
335+
ProjectionElem::Deref => {
336+
trace!("processing deref");
337+
eval = self.use_ecx(source_info, |this| {
338+
this.ecx.deref_operand(eval)
339+
})?.into();
340+
}
336341
// We could get more projections by using e.g., `operand_projection`,
337342
// but we do not even have the stack frame set up properly so
338343
// an `Index` projection would throw us off-track.
@@ -363,8 +368,12 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
363368
Rvalue::Use(ref op) => {
364369
self.eval_operand(op, source_info)
365370
},
371+
Rvalue::Ref(_, _, ref place) => {
372+
let src = self.eval_place(place, source_info)?;
373+
let mplace = src.try_as_mplace().ok()?;
374+
Some(ImmTy::from_scalar(mplace.ptr.into(), place_layout).into())
375+
},
366376
Rvalue::Repeat(..) |
367-
Rvalue::Ref(..) |
368377
Rvalue::Aggregate(..) |
369378
Rvalue::NullaryOp(NullOp::Box, _) |
370379
Rvalue::Discriminant(..) => None,
@@ -376,10 +385,30 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
376385
this.ecx.cast(op, kind, dest.into())?;
377386
Ok(dest.into())
378387
})
379-
}
388+
},
389+
Rvalue::Len(ref place) => {
390+
let place = self.eval_place(&place, source_info)?;
391+
let mplace = place.try_as_mplace().ok()?;
392+
393+
if let ty::Slice(_) = mplace.layout.ty.sty {
394+
let len = mplace.meta.unwrap().to_usize(&self.ecx).unwrap();
380395

381-
// FIXME(oli-obk): evaluate static/constant slice lengths
382-
Rvalue::Len(_) => None,
396+
Some(ImmTy {
397+
imm: Immediate::Scalar(
398+
Scalar::from_uint(
399+
len,
400+
Size::from_bits(
401+
self.tcx.sess.target.usize_ty.bit_width().unwrap() as u64
402+
)
403+
).into(),
404+
),
405+
layout: self.tcx.layout_of(self.param_env.and(self.tcx.types.usize)).ok()?,
406+
}.into())
407+
} else {
408+
trace!("not slice: {:?}", mplace.layout.ty.sty);
409+
None
410+
}
411+
},
383412
Rvalue::NullaryOp(NullOp::SizeOf, ty) => {
384413
type_size_of(self.tcx, self.param_env, ty).and_then(|n| Some(
385414
ImmTy {
@@ -525,12 +554,10 @@ impl<'a, 'mir, 'tcx> ConstPropagator<'a, 'mir, 'tcx> {
525554
source_info: SourceInfo,
526555
) {
527556
trace!("attepting to replace {:?} with {:?}", rval, value);
528-
self.ecx.validate_operand(
529-
value,
530-
vec![],
531-
None,
532-
true,
533-
).expect("value should already be a valid const");
557+
if let Err(e) = self.ecx.validate_operand(value, vec![], None, true) {
558+
trace!("validation error, attempt failed: {:?}", e);
559+
return;
560+
}
534561

535562
// FIXME> figure out what tho do when try_read_immediate fails
536563
let imm = self.use_ecx(source_info, |this| {
+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
fn main() {
2+
*(&4);
3+
}
4+
5+
// END RUST SOURCE
6+
// START rustc.main.ConstProp.before.mir
7+
// bb0: {
8+
// ...
9+
// _2 = &(promoted[0]: i32);
10+
// _1 = (*_2);
11+
// ...
12+
//}
13+
// END rustc.main.ConstProp.before.mir
14+
// START rustc.main.ConstProp.after.mir
15+
// bb0: {
16+
// ...
17+
// _2 = const Scalar(AllocId(0).0x0) : &i32;
18+
// _1 = const 4i32;
19+
// ...
20+
// }
21+
// END rustc.main.ConstProp.after.mir
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
fn main() {
2+
let _ = main as usize as *const fn();
3+
}
4+
5+
// END RUST SOURCE
6+
// START rustc.main.ConstProp.before.mir
7+
// bb0: {
8+
// ...
9+
// _3 = const main as fn() (Pointer(ReifyFnPointer));
10+
// _2 = move _3 as usize (Misc);
11+
// ...
12+
// _1 = move _2 as *const fn() (Misc);
13+
// ...
14+
// }
15+
// END rustc.main.ConstProp.before.mir
16+
// START rustc.main.ConstProp.after.mir
17+
// bb0: {
18+
// ...
19+
// _3 = const Scalar(AllocId(1).0x0) : fn();
20+
// _2 = move _3 as usize (Misc);
21+
// ...
22+
// _1 = const Scalar(AllocId(1).0x0) : *const fn();
23+
// ...
24+
// }
25+
// END rustc.main.ConstProp.after.mir

src/test/mir-opt/const_prop/slice_len.rs

+22-18
Original file line numberDiff line numberDiff line change
@@ -1,36 +1,40 @@
1-
fn test() -> &'static [u32] {
2-
&[1, 2]
3-
}
4-
51
fn main() {
6-
let x = test()[0];
2+
(&[1u32, 2, 3] as &[u32])[1];
73
}
84

95
// END RUST SOURCE
106
// START rustc.main.ConstProp.before.mir
11-
// bb1: {
7+
// bb0: {
128
// ...
13-
// _3 = const 0usize;
14-
// _4 = Len((*_2));
15-
// _5 = Lt(_3, _4);
16-
// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
9+
// _4 = &(promoted[0]: [u32; 3]);
10+
// _3 = _4;
11+
// _2 = move _3 as &[u32] (Pointer(Unsize));
12+
// ...
13+
// _6 = const 1usize;
14+
// _7 = Len((*_2));
15+
// _8 = Lt(_6, _7);
16+
// assert(move _8, "index out of bounds: the len is move _7 but the index is _6") -> bb1;
1717
// }
18-
// bb2: {
19-
// _1 = (*_2)[_3];
18+
// bb1: {
19+
// _1 = (*_2)[_6];
2020
// ...
2121
// return;
2222
// }
2323
// END rustc.main.ConstProp.before.mir
2424
// START rustc.main.ConstProp.after.mir
2525
// bb0: {
2626
// ...
27-
// _3 = const 0usize;
28-
// _4 = Len((*_2));
29-
// _5 = Lt(_3, _4);
30-
// assert(move _5, "index out of bounds: the len is move _4 but the index is _3") -> bb2;
27+
// _4 = const Scalar(AllocId(0).0x0) : &[u32; 3];
28+
// _3 = const Scalar(AllocId(0).0x0) : &[u32; 3];
29+
// _2 = move _3 as &[u32] (Pointer(Unsize));
30+
// ...
31+
// _6 = const 1usize;
32+
// _7 = const 3usize;
33+
// _8 = const true;
34+
// assert(const true, "index out of bounds: the len is move _7 but the index is _6") -> bb1;
3135
// }
32-
// bb2: {
33-
// _1 = (*_2)[_3];
36+
// bb1: {
37+
// _1 = (*_2)[_6];
3438
// ...
3539
// return;
3640
// }

src/test/ui/access-mode-in-closures.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@ LL | match *s { S(v) => v }
66
| | |
77
| | data moved here
88
| | move occurs because `v` has type `std::vec::Vec<isize>`, which does not implement the `Copy` trait
9-
| help: consider removing the `*`: `s`
9+
| help: consider borrowing here: `&*s`
1010

1111
error: aborting due to previous error
1212

src/test/ui/borrowck/borrowck-issue-2657-2.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | let _b = *y;
55
| ^^
66
| |
77
| move occurs because `*y` has type `std::boxed::Box<i32>`, which does not implement the `Copy` trait
8-
| help: consider removing the `*`: `y`
8+
| help: consider borrowing here: `&*y`
99

1010
error: aborting due to previous error
1111

src/test/ui/borrowck/borrowck-move-error-with-note.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@ error[E0507]: cannot move out of `f.0` which is behind a shared reference
22
--> $DIR/borrowck-move-error-with-note.rs:11:11
33
|
44
LL | match *f {
5-
| ^^ help: consider removing the `*`: `f`
5+
| ^^ help: consider borrowing here: `&*f`
66
LL | Foo::Foo1(num1,
77
| ---- data moved here
88
LL | num2) => (),

src/test/ui/borrowck/borrowck-move-from-unsafe-ptr.stderr

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,7 +5,7 @@ LL | let y = *x;
55
| ^^
66
| |
77
| move occurs because `*x` has type `std::boxed::Box<isize>`, which does not implement the `Copy` trait
8-
| help: consider removing the `*`: `x`
8+
| help: consider borrowing here: `&*x`
99

1010
error: aborting due to previous error
1111

0 commit comments

Comments
 (0)