Skip to content

Commit 18fcb3f

Browse files
committed
Prevent copies for unsized fn params
1 parent 33a01e2 commit 18fcb3f

File tree

5 files changed

+84
-39
lines changed

5 files changed

+84
-39
lines changed

compiler/rustc_mir_build/src/build/expr/as_operand.rs

+5-2
Original file line numberDiff line numberDiff line change
@@ -163,8 +163,6 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
163163
// !sized means !copy, so this is an unsized move
164164
assert!(!ty.is_copy_modulo_regions(tcx, param_env));
165165

166-
// As described above, detect the case where we are passing a value of unsized
167-
// type, and that value is coming from the deref of a box.
168166
if let ExprKind::Deref { arg } = expr.kind {
169167
// Generate let tmp0 = arg0
170168
let operand = unpack!(
@@ -177,6 +175,11 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
177175
projection: tcx.mk_place_elems(&[PlaceElem::Deref]),
178176
};
179177

178+
return block.and(Operand::Move(place));
179+
} else {
180+
// FIXME: This does not prevent the place from being modified before being used,
181+
// see `tests/mir-opt/unsized_arg_forwarding.rs`.
182+
let place = unpack!(block = this.as_place(block, expr));
180183
return block.and(Operand::Move(place));
181184
}
182185
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,47 @@
1+
// MIR for `forward` after built
2+
3+
fn forward(_1: [usize], _2: usize) -> () {
4+
debug x => _1; // in scope 0 at $DIR/unsized_arg_forwarding.rs:+0:12: +0:17
5+
debug i => _2; // in scope 0 at $DIR/unsized_arg_forwarding.rs:+0:28: +0:29
6+
let mut _0: (); // return place in scope 0 at $DIR/unsized_arg_forwarding.rs:+0:38: +0:38
7+
let _3: (); // in scope 0 at $DIR/unsized_arg_forwarding.rs:+4:5: +7:7
8+
let mut _4: (); // in scope 0 at $DIR/unsized_arg_forwarding.rs:+4:12: +7:6
9+
let mut _5: usize; // in scope 0 at $DIR/unsized_arg_forwarding.rs:+5:16: +5:17
10+
let _6: usize; // in scope 0 at $DIR/unsized_arg_forwarding.rs:+5:11: +5:12
11+
let mut _7: usize; // in scope 0 at $DIR/unsized_arg_forwarding.rs:+5:9: +5:13
12+
let mut _8: bool; // in scope 0 at $DIR/unsized_arg_forwarding.rs:+5:9: +5:13
13+
14+
bb0: {
15+
StorageLive(_3); // scope 0 at $DIR/unsized_arg_forwarding.rs:+4:5: +7:7
16+
StorageLive(_4); // scope 0 at $DIR/unsized_arg_forwarding.rs:+4:12: +7:6
17+
StorageLive(_5); // scope 0 at $DIR/unsized_arg_forwarding.rs:+5:16: +5:17
18+
_5 = _2; // scope 0 at $DIR/unsized_arg_forwarding.rs:+5:16: +5:17
19+
StorageLive(_6); // scope 0 at $DIR/unsized_arg_forwarding.rs:+5:11: +5:12
20+
_6 = _2; // scope 0 at $DIR/unsized_arg_forwarding.rs:+5:11: +5:12
21+
_7 = Len(_1); // scope 0 at $DIR/unsized_arg_forwarding.rs:+5:9: +5:13
22+
_8 = Lt(_6, _7); // scope 0 at $DIR/unsized_arg_forwarding.rs:+5:9: +5:13
23+
assert(move _8, "index out of bounds: the length is {} but the index is {}", move _7, _6) -> [success: bb1, unwind: bb3]; // scope 0 at $DIR/unsized_arg_forwarding.rs:+5:9: +5:13
24+
}
25+
26+
bb1: {
27+
_1[_6] = move _5; // scope 0 at $DIR/unsized_arg_forwarding.rs:+5:9: +5:17
28+
StorageDead(_5); // scope 0 at $DIR/unsized_arg_forwarding.rs:+5:16: +5:17
29+
StorageDead(_6); // scope 0 at $DIR/unsized_arg_forwarding.rs:+5:17: +5:18
30+
_4 = (); // scope 0 at $DIR/unsized_arg_forwarding.rs:+6:9: +6:11
31+
_3 = nop(move _1, move _4) -> [return: bb2, unwind: bb3]; // scope 0 at $DIR/unsized_arg_forwarding.rs:+4:5: +7:7
32+
// mir::Constant
33+
// + span: $DIR/unsized_arg_forwarding.rs:10:5: 10:8
34+
// + literal: Const { ty: fn([usize], ()) {nop}, val: Value(<ZST>) }
35+
}
36+
37+
bb2: {
38+
StorageDead(_4); // scope 0 at $DIR/unsized_arg_forwarding.rs:+7:6: +7:7
39+
StorageDead(_3); // scope 0 at $DIR/unsized_arg_forwarding.rs:+7:7: +7:8
40+
_0 = const (); // scope 0 at $DIR/unsized_arg_forwarding.rs:+0:38: +8:2
41+
return; // scope 0 at $DIR/unsized_arg_forwarding.rs:+8:2: +8:2
42+
}
43+
44+
bb3 (cleanup): {
45+
resume; // scope 0 at $DIR/unsized_arg_forwarding.rs:+0:1: +8:2
46+
}
47+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,19 @@
1+
#![feature(unsized_fn_params)]
2+
3+
fn nop(_: [usize], _: ()) {}
4+
5+
// EMIT_MIR unsized_arg_forwarding.forward.built.after.mir
6+
fn forward(mut x: [usize], i: usize) {
7+
// Check that we do not copy `x` into a temporary. Unfortunately this means that the write to
8+
// `x[0]` does not result in a borrowck error. There is currently no way to generate Mir that
9+
// does not exhibit this bug.
10+
nop(x, {
11+
x[i] = i;
12+
()
13+
});
14+
}
15+
16+
fn main() {
17+
let x: Box<[usize]> = Box::new([1]);
18+
forward(*x, 0);
19+
}

tests/ui/unsized-locals/borrow-after-move.stderr

+8-18
Original file line numberDiff line numberDiff line change
@@ -24,28 +24,24 @@ error[E0382]: borrow of moved value: `y`
2424
LL | let y = *x;
2525
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
2626
LL | drop_unsized(y);
27-
| - value moved here
27+
| --------------- value moved here
2828
...
2929
LL | println!("{}", &y);
3030
| ^^ value borrowed here after move
31-
|
32-
note: consider changing this parameter type in function `drop_unsized` to borrow instead if owning the value isn't necessary
33-
--> $DIR/borrow-after-move.rs:14:31
34-
|
35-
LL | fn drop_unsized<T: ?Sized>(_: T) {}
36-
| ------------ ^ this parameter takes ownership of the value
37-
| |
38-
| in this function
3931

4032
error[E0382]: borrow of moved value: `x`
4133
--> $DIR/borrow-after-move.rs:31:24
4234
|
43-
LL | let y = *x;
44-
| -- value moved here
4535
LL | y.foo();
36+
| ----- `*x` moved due to this method call
4637
LL | println!("{}", &x);
4738
| ^^ value borrowed here after move
4839
|
40+
note: `Foo::foo` takes ownership of the receiver `self`, which moves `*x`
41+
--> $DIR/borrow-after-move.rs:5:12
42+
|
43+
LL | fn foo(self) -> String;
44+
| ^^^^
4945
= note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
5046

5147
error[E0382]: borrow of moved value: `y`
@@ -54,16 +50,10 @@ error[E0382]: borrow of moved value: `y`
5450
LL | let y = *x;
5551
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
5652
LL | y.foo();
57-
| ----- `y` moved due to this method call
53+
| ------- value moved here
5854
...
5955
LL | println!("{}", &y);
6056
| ^^ value borrowed here after move
61-
|
62-
note: `Foo::foo` takes ownership of the receiver `self`, which moves `y`
63-
--> $DIR/borrow-after-move.rs:5:12
64-
|
65-
LL | fn foo(self) -> String;
66-
| ^^^^
6757

6858
error[E0382]: borrow of moved value: `x`
6959
--> $DIR/borrow-after-move.rs:40:24

tests/ui/unsized-locals/double-move.stderr

+5-19
Original file line numberDiff line numberDiff line change
@@ -8,22 +8,14 @@ LL | #![feature(unsized_locals, unsized_fn_params)]
88
= note: `#[warn(incomplete_features)]` on by default
99

1010
error[E0382]: use of moved value: `y`
11-
--> $DIR/double-move.rs:21:22
11+
--> $DIR/double-move.rs:21:9
1212
|
1313
LL | let y = *x;
1414
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
1515
LL | drop_unsized(y);
16-
| - value moved here
16+
| --------------- value moved here
1717
LL | drop_unsized(y);
18-
| ^ value used here after move
19-
|
20-
note: consider changing this parameter type in function `drop_unsized` to borrow instead if owning the value isn't necessary
21-
--> $DIR/double-move.rs:14:31
22-
|
23-
LL | fn drop_unsized<T: ?Sized>(_: T) {}
24-
| ------------ ^ this parameter takes ownership of the value
25-
| |
26-
| in this function
18+
| ^^^^^^^^^^^^^^^ value used here after move
2719

2820
error[E0382]: use of moved value: `x`
2921
--> $DIR/double-move.rs:27:22
@@ -51,15 +43,9 @@ error[E0382]: use of moved value: `y`
5143
LL | let y = *x;
5244
| - move occurs because `y` has type `str`, which does not implement the `Copy` trait
5345
LL | y.foo();
54-
| ----- `y` moved due to this method call
46+
| ------- value moved here
5547
LL | y.foo();
56-
| ^ value used here after move
57-
|
58-
note: `Foo::foo` takes ownership of the receiver `self`, which moves `y`
59-
--> $DIR/double-move.rs:5:12
60-
|
61-
LL | fn foo(self) -> String;
62-
| ^^^^
48+
| ^^^^^^^ value used here after move
6349

6450
error[E0382]: use of moved value: `x`
6551
--> $DIR/double-move.rs:46:9

0 commit comments

Comments
 (0)