Skip to content

Commit d7cbb08

Browse files
committed
Move the place in &pin mut $place to ensure soundness
1 parent 40997dc commit d7cbb08

File tree

5 files changed

+173
-81
lines changed

5 files changed

+173
-81
lines changed

compiler/rustc_mir_build/src/thir/cx/expr.rs

+28-3
Original file line numberDiff line numberDiff line change
@@ -477,15 +477,40 @@ impl<'tcx> ThirBuildCx<'tcx> {
477477
}
478478

479479
// Make `&pin mut $expr` and `&pin const $expr` into
480-
// `Pin { __pointer: &mut $expr }` and `Pin { __pointer: &$expr }`.
480+
// `Pin { __pointer: &mut { $expr } }` and `Pin { __pointer: &$expr }`.
481481
hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg) => match expr_ty.kind() {
482482
&ty::Adt(adt_def, args)
483483
if tcx.is_lang_item(adt_def.did(), rustc_hir::LangItem::Pin) =>
484484
{
485-
let arg = self.mirror_expr(arg);
485+
let ty = args.type_at(0);
486+
let arg_ty = self.typeck_results.expr_ty(arg);
487+
let mut arg = self.mirror_expr(arg);
488+
// for `&pin mut $place`, move the place `$place` to ensure it will not be used afterwards
489+
if mutbl.is_mut() {
490+
let block = self.thir.blocks.push(Block {
491+
targeted_by_break: false,
492+
region_scope: region::Scope {
493+
local_id: expr.hir_id.local_id,
494+
data: region::ScopeData::Node,
495+
},
496+
span: expr.span,
497+
stmts: Box::new([]),
498+
expr: Some(arg),
499+
safety_mode: BlockSafety::Safe,
500+
});
501+
arg = self.thir.exprs.push(Expr {
502+
temp_lifetime: TempLifetime {
503+
temp_lifetime: None,
504+
backwards_incompatible: None,
505+
},
506+
ty: arg_ty,
507+
span: expr.span,
508+
kind: ExprKind::Block { block },
509+
});
510+
}
486511
let expr = self.thir.exprs.push(Expr {
487512
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
488-
ty: args.type_at(0),
513+
ty,
489514
span: expr.span,
490515
kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg },
491516
});

tests/ui/pin-ergonomics/borrow-mut-xor-share.rs

+13-10
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,10 @@
11
#![feature(pin_ergonomics)]
22
#![allow(dead_code, incomplete_features)]
33

4-
// Makes sure `&pin mut place` and `&pin const place` cannot violate the mut-xor-share rules.
4+
// For now, we move the place in `&pin mut place` to ensure soundness.
5+
// In the next step, we borrow the place instead of moving it, after that we
6+
// have to makes sure `&pin mut place` and `&pin const place` cannot violate
7+
// the mut-xor-share rules.
58

69
use std::pin::Pin;
710

@@ -21,37 +24,37 @@ fn foo_pin_ref(_: Pin<&Foo>) {
2124

2225
fn bar() {
2326
let foo = Foo;
24-
foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable
27+
foo_pin_mut(&pin mut foo); // ok because `foo` is moved`
2528

2629
let mut foo = Foo;
2730
let x = &pin mut foo;
28-
foo_pin_ref(&pin const foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
29-
foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time
30-
foo_ref(&foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
31-
foo_mut(&mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time
31+
foo_pin_ref(&pin const foo); //~ ERROR borrow of moved value: `foo`
32+
foo_pin_mut(&pin mut foo); // ok
33+
foo_ref(&foo); //~ ERROR borrow of moved value: `foo`
34+
foo_mut(&mut foo); // ok
3235

3336
foo_pin_mut(x);
3437

3538
let mut foo = Foo;
3639
let x = &pin const foo;
3740
foo_pin_ref(&pin const foo); // ok
38-
foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable
39-
foo_ref(&foo); // ok
41+
foo_pin_mut(&pin mut foo); //~ ERROR cannot move out of `foo` because it is borrowed
42+
foo_ref(&foo); //~ ERROR borrow of moved value: `foo`
4043
foo_mut(&mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable
4144

4245
foo_pin_ref(x);
4346

4447
let mut foo = Foo;
4548
let x = &mut foo;
4649
foo_pin_ref(&pin const foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
47-
foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time
50+
foo_pin_mut(&pin mut foo); //~ ERROR cannot move out of `foo` because it is borrowed
4851

4952
foo_mut(x);
5053

5154
let mut foo = Foo;
5255
let x = &foo;
5356
foo_pin_ref(&pin const foo); // ok
54-
foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable
57+
foo_pin_mut(&pin mut foo); //~ ERROR cannot move out of `foo` because it is borrowed
5558

5659
foo_ref(x);
5760
}
Original file line numberDiff line numberDiff line change
@@ -1,75 +1,87 @@
1-
error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable
2-
--> $DIR/borrow-mut-xor-share.rs:24:17
3-
|
4-
LL | foo_pin_mut(&pin mut foo);
5-
| ^^^^^^^^^^^^ cannot borrow as mutable
6-
|
7-
help: consider changing this to be mutable
1+
error[E0382]: borrow of moved value: `foo`
2+
--> $DIR/borrow-mut-xor-share.rs:31:17
83
|
94
LL | let mut foo = Foo;
10-
| +++
11-
12-
error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
13-
--> $DIR/borrow-mut-xor-share.rs:28:17
14-
|
5+
| ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
156
LL | let x = &pin mut foo;
16-
| ------------ mutable borrow occurs here
7+
| --- value moved here
178
LL | foo_pin_ref(&pin const foo);
18-
| ^^^^^^^^^^^^^^ immutable borrow occurs here
19-
...
20-
LL | foo_pin_mut(x);
21-
| - mutable borrow later used here
22-
23-
error[E0499]: cannot borrow `foo` as mutable more than once at a time
24-
--> $DIR/borrow-mut-xor-share.rs:29:17
9+
| ^^^^^^^^^^^^^^ value borrowed here after move
2510
|
26-
LL | let x = &pin mut foo;
27-
| ------------ first mutable borrow occurs here
28-
LL | foo_pin_ref(&pin const foo);
29-
LL | foo_pin_mut(&pin mut foo);
30-
| ^^^^^^^^^^^^ second mutable borrow occurs here
11+
note: if `Foo` implemented `Clone`, you could clone the value
12+
--> $DIR/borrow-mut-xor-share.rs:11:1
13+
|
14+
LL | struct Foo;
15+
| ^^^^^^^^^^ consider implementing `Clone` for this type
3116
...
32-
LL | foo_pin_mut(x);
33-
| - first borrow later used here
17+
LL | let x = &pin mut foo;
18+
| --- you could clone this value
3419

35-
error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
36-
--> $DIR/borrow-mut-xor-share.rs:30:13
20+
error[E0382]: borrow of moved value: `foo`
21+
--> $DIR/borrow-mut-xor-share.rs:33:13
3722
|
38-
LL | let x = &pin mut foo;
39-
| ------------ mutable borrow occurs here
23+
LL | let mut foo = Foo;
24+
| ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
4025
...
26+
LL | foo_pin_mut(&pin mut foo); // ok
27+
| --- value moved here
4128
LL | foo_ref(&foo);
42-
| ^^^^ immutable borrow occurs here
43-
...
44-
LL | foo_pin_mut(x);
45-
| - mutable borrow later used here
46-
47-
error[E0499]: cannot borrow `foo` as mutable more than once at a time
48-
--> $DIR/borrow-mut-xor-share.rs:31:13
29+
| ^^^^ value borrowed here after move
4930
|
50-
LL | let x = &pin mut foo;
51-
| ------------ first mutable borrow occurs here
31+
note: if `Foo` implemented `Clone`, you could clone the value
32+
--> $DIR/borrow-mut-xor-share.rs:11:1
33+
|
34+
LL | struct Foo;
35+
| ^^^^^^^^^^ consider implementing `Clone` for this type
5236
...
53-
LL | foo_mut(&mut foo);
54-
| ^^^^^^^^ second mutable borrow occurs here
55-
LL |
56-
LL | foo_pin_mut(x);
57-
| - first borrow later used here
37+
LL | foo_pin_mut(&pin mut foo); // ok
38+
| --- you could clone this value
5839

59-
error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
60-
--> $DIR/borrow-mut-xor-share.rs:38:17
40+
error[E0505]: cannot move out of `foo` because it is borrowed
41+
--> $DIR/borrow-mut-xor-share.rs:41:26
6142
|
43+
LL | let mut foo = Foo;
44+
| ------- binding `foo` declared here
6245
LL | let x = &pin const foo;
63-
| -------------- immutable borrow occurs here
46+
| -------------- borrow of `foo` occurs here
6447
LL | foo_pin_ref(&pin const foo); // ok
6548
LL | foo_pin_mut(&pin mut foo);
66-
| ^^^^^^^^^^^^ mutable borrow occurs here
49+
| ^^^ move out of `foo` occurs here
6750
...
6851
LL | foo_pin_ref(x);
69-
| - immutable borrow later used here
52+
| - borrow later used here
53+
|
54+
note: if `Foo` implemented `Clone`, you could clone the value
55+
--> $DIR/borrow-mut-xor-share.rs:11:1
56+
|
57+
LL | struct Foo;
58+
| ^^^^^^^^^^ consider implementing `Clone` for this type
59+
...
60+
LL | let x = &pin const foo;
61+
| --- you could clone this value
62+
63+
error[E0382]: borrow of moved value: `foo`
64+
--> $DIR/borrow-mut-xor-share.rs:42:13
65+
|
66+
LL | let mut foo = Foo;
67+
| ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
68+
...
69+
LL | foo_pin_mut(&pin mut foo);
70+
| --- value moved here
71+
LL | foo_ref(&foo);
72+
| ^^^^ value borrowed here after move
73+
|
74+
note: if `Foo` implemented `Clone`, you could clone the value
75+
--> $DIR/borrow-mut-xor-share.rs:11:1
76+
|
77+
LL | struct Foo;
78+
| ^^^^^^^^^^ consider implementing `Clone` for this type
79+
...
80+
LL | foo_pin_mut(&pin mut foo);
81+
| --- you could clone this value
7082

7183
error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
72-
--> $DIR/borrow-mut-xor-share.rs:40:13
84+
--> $DIR/borrow-mut-xor-share.rs:43:13
7385
|
7486
LL | let x = &pin const foo;
7587
| -------------- immutable borrow occurs here
@@ -81,7 +93,7 @@ LL | foo_pin_ref(x);
8193
| - immutable borrow later used here
8294

8395
error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
84-
--> $DIR/borrow-mut-xor-share.rs:46:17
96+
--> $DIR/borrow-mut-xor-share.rs:49:17
8597
|
8698
LL | let x = &mut foo;
8799
| -------- mutable borrow occurs here
@@ -91,31 +103,53 @@ LL | foo_pin_ref(&pin const foo);
91103
LL | foo_mut(x);
92104
| - mutable borrow later used here
93105

94-
error[E0499]: cannot borrow `foo` as mutable more than once at a time
95-
--> $DIR/borrow-mut-xor-share.rs:47:17
106+
error[E0505]: cannot move out of `foo` because it is borrowed
107+
--> $DIR/borrow-mut-xor-share.rs:50:26
96108
|
109+
LL | let mut foo = Foo;
110+
| ------- binding `foo` declared here
97111
LL | let x = &mut foo;
98-
| -------- first mutable borrow occurs here
112+
| -------- borrow of `foo` occurs here
99113
LL | foo_pin_ref(&pin const foo);
100114
LL | foo_pin_mut(&pin mut foo);
101-
| ^^^^^^^^^^^^ second mutable borrow occurs here
115+
| ^^^ move out of `foo` occurs here
102116
LL |
103117
LL | foo_mut(x);
104-
| - first borrow later used here
118+
| - borrow later used here
119+
|
120+
note: if `Foo` implemented `Clone`, you could clone the value
121+
--> $DIR/borrow-mut-xor-share.rs:11:1
122+
|
123+
LL | struct Foo;
124+
| ^^^^^^^^^^ consider implementing `Clone` for this type
125+
...
126+
LL | let x = &mut foo;
127+
| --- you could clone this value
105128

106-
error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
107-
--> $DIR/borrow-mut-xor-share.rs:54:17
129+
error[E0505]: cannot move out of `foo` because it is borrowed
130+
--> $DIR/borrow-mut-xor-share.rs:57:26
108131
|
132+
LL | let mut foo = Foo;
133+
| ------- binding `foo` declared here
109134
LL | let x = &foo;
110-
| ---- immutable borrow occurs here
135+
| ---- borrow of `foo` occurs here
111136
LL | foo_pin_ref(&pin const foo); // ok
112137
LL | foo_pin_mut(&pin mut foo);
113-
| ^^^^^^^^^^^^ mutable borrow occurs here
138+
| ^^^ move out of `foo` occurs here
114139
LL |
115140
LL | foo_ref(x);
116-
| - immutable borrow later used here
141+
| - borrow later used here
142+
|
143+
note: if `Foo` implemented `Clone`, you could clone the value
144+
--> $DIR/borrow-mut-xor-share.rs:11:1
145+
|
146+
LL | struct Foo;
147+
| ^^^^^^^^^^ consider implementing `Clone` for this type
148+
...
149+
LL | let x = &foo;
150+
| --- you could clone this value
117151

118-
error: aborting due to 10 previous errors
152+
error: aborting due to 8 previous errors
119153

120-
Some errors have detailed explanations: E0499, E0502, E0596.
121-
For more information about an error, try `rustc --explain E0499`.
154+
Some errors have detailed explanations: E0382, E0502, E0505.
155+
For more information about an error, try `rustc --explain E0382`.

tests/ui/pin-ergonomics/borrow.rs

+10-3
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,8 @@
1-
//@ check-pass
2-
31
#![feature(pin_ergonomics)]
42
#![allow(dead_code, incomplete_features)]
53

64
// Makes sure we can handle `&pin mut place` and `&pin const place` as sugar for
7-
// `unsafe { Pin::new_unchecked(&mut place) }` and `Pin::new(&place)`.
5+
// `std::pin::pin!(place)` and `Pin::new(&place)`.
86

97
use std::pin::Pin;
108

@@ -28,4 +26,13 @@ fn bar() {
2826
foo_pin_ref(x);
2927
}
3028

29+
fn baz(mut x: Foo, y: Foo) {
30+
// For now, `x` is moved to ensure soundness of creating this `Pin<&mut Foo>`.
31+
let _x = &pin mut x;
32+
let _x = x; //~ ERROR use of moved value: `x`
33+
34+
let _y = &pin const y;
35+
let _y = y; // ok because `&pin const y` dosn't move `y`
36+
}
37+
3138
fn main() {}

tests/ui/pin-ergonomics/borrow.stderr

+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
error[E0382]: use of moved value: `x`
2+
--> $DIR/borrow.rs:32:14
3+
|
4+
LL | fn baz(mut x: Foo, y: Foo) {
5+
| ----- move occurs because `x` has type `Foo`, which does not implement the `Copy` trait
6+
LL | // For now, `x` is moved to ensure soundness of creating this `Pin<&mut Foo>`.
7+
LL | let _x = &pin mut x;
8+
| - value moved here
9+
LL | let _x = x;
10+
| ^ value used here after move
11+
|
12+
note: if `Foo` implemented `Clone`, you could clone the value
13+
--> $DIR/borrow.rs:9:1
14+
|
15+
LL | struct Foo;
16+
| ^^^^^^^^^^ consider implementing `Clone` for this type
17+
...
18+
LL | let _x = &pin mut x;
19+
| - you could clone this value
20+
21+
error: aborting due to 1 previous error
22+
23+
For more information about this error, try `rustc --explain E0382`.

0 commit comments

Comments
 (0)