Skip to content

Commit 1c081ea

Browse files
committed
Implement pinned borrows, part of pin_ergonomics
1 parent 30508fa commit 1c081ea

File tree

15 files changed

+441
-10
lines changed

15 files changed

+441
-10
lines changed

compiler/rustc_ast/src/ast.rs

+4
Original file line numberDiff line numberDiff line change
@@ -866,6 +866,10 @@ pub enum BorrowKind {
866866
/// The resulting type is either `*const T` or `*mut T`
867867
/// where `T = typeof($expr)`.
868868
Raw,
869+
/// A pinned borrow, `&pin const $expr` or `&pin mut $expr`.
870+
/// The resulting type is either `Pin<&'a T>` or `Pin<&'a mut T>`
871+
/// where `T = typeof($expr)` and `'a` is some lifetime.
872+
Pin,
869873
}
870874

871875
#[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]

compiler/rustc_ast_pretty/src/pprust/state/expr.rs

+4
Original file line numberDiff line numberDiff line change
@@ -339,6 +339,10 @@ impl<'a> State<'a> {
339339
self.word_nbsp("raw");
340340
self.print_mutability(mutability, true);
341341
}
342+
ast::BorrowKind::Pin => {
343+
self.word_nbsp("pin");
344+
self.print_mutability(mutability, true);
345+
}
342346
}
343347
self.print_expr_cond_paren(
344348
expr,

compiler/rustc_const_eval/src/check_consts/ops.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -619,11 +619,13 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
619619
kind: ccx.const_kind(),
620620
teach: ccx.tcx.sess.teach(E0764),
621621
}),
622-
hir::BorrowKind::Ref => ccx.dcx().create_err(errors::MutableRefEscaping {
623-
span,
624-
kind: ccx.const_kind(),
625-
teach: ccx.tcx.sess.teach(E0764),
626-
}),
622+
hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
623+
ccx.dcx().create_err(errors::MutableRefEscaping {
624+
span,
625+
kind: ccx.const_kind(),
626+
teach: ccx.tcx.sess.teach(E0764),
627+
})
628+
}
627629
}
628630
}
629631
}

compiler/rustc_hir_pretty/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1343,6 +1343,10 @@ impl<'a> State<'a> {
13431343
self.word_nbsp("raw");
13441344
self.print_mutability(mutability, true);
13451345
}
1346+
hir::BorrowKind::Pin => {
1347+
self.word_nbsp("pin");
1348+
self.print_mutability(mutability, true);
1349+
}
13461350
}
13471351
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Prefix);
13481352
}

compiler/rustc_hir_typeck/src/expr.rs

+5
Original file line numberDiff line numberDiff line change
@@ -688,6 +688,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
688688
let region = self.next_region_var(infer::BorrowRegion(expr.span));
689689
Ty::new_ref(self.tcx, region, ty, mutbl)
690690
}
691+
hir::BorrowKind::Pin => {
692+
// See comments in the `hir::BorrowKind::Ref` arm above.
693+
let region = self.next_region_var(infer::BorrowRegion(expr.span));
694+
Ty::new_pinned_ref(self.tcx, region, ty, mutbl)
695+
}
691696
}
692697
}
693698

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

+25
Original file line numberDiff line numberDiff line change
@@ -472,6 +472,31 @@ impl<'tcx> ThirBuildCx<'tcx> {
472472
ExprKind::RawBorrow { mutability, arg: self.mirror_expr(arg) }
473473
}
474474

475+
// make `&pin mut $expr` and `&pin const $expr` into `Pin { __pointer: &mut $expr }`
476+
// and `Pin { __pointer: &$expr }`
477+
hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg) => match expr_ty.kind() {
478+
&ty::Adt(adt_def, args)
479+
if tcx.is_lang_item(adt_def.did(), rustc_hir::LangItem::Pin) =>
480+
{
481+
let arg = self.mirror_expr(arg);
482+
let expr = self.thir.exprs.push(Expr {
483+
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
484+
ty: args.type_at(0),
485+
span: expr.span,
486+
kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg },
487+
});
488+
ExprKind::Adt(Box::new(AdtExpr {
489+
adt_def,
490+
variant_index: FIRST_VARIANT,
491+
args,
492+
fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
493+
user_ty: None,
494+
base: AdtExprBase::None,
495+
}))
496+
}
497+
_ => span_bug!(expr.span, "unexpected type for pinned borrow: {:?}", expr_ty),
498+
},
499+
475500
hir::ExprKind::Block(blk, _) => ExprKind::Block { block: self.mirror_block(blk) },
476501

477502
hir::ExprKind::Assign(lhs, rhs, _) => {

compiler/rustc_parse/src/parser/expr.rs

+4
Original file line numberDiff line numberDiff line change
@@ -836,6 +836,10 @@ impl<'a> Parser<'a> {
836836
assert!(found_raw);
837837
let mutability = self.parse_const_or_mut().unwrap();
838838
(ast::BorrowKind::Raw, mutability)
839+
} else if let Some((ast::Pinnedness::Pinned, mutbl)) = self.parse_pin_and_mut() {
840+
// `pin [ const | mut ]`.
841+
// `pin` has been gated in `self.parse_pin_and_mut()` so we don't need to gate it here.
842+
(ast::BorrowKind::Pin, mutbl)
839843
} else {
840844
// `mut?`
841845
(ast::BorrowKind::Ref, self.parse_mutability())

src/tools/rustfmt/src/expr.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2285,8 +2285,10 @@ fn rewrite_expr_addrof(
22852285
let operator_str = match (mutability, borrow_kind) {
22862286
(ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
22872287
(ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
2288+
(ast::Mutability::Not, ast::BorrowKind::Pin) => "&pin const ",
22882289
(ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
22892290
(ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
2291+
(ast::Mutability::Mut, ast::BorrowKind::Pin) => "&pin mut ",
22902292
};
22912293
rewrite_unary_prefix(context, operator_str, expr, shape)
22922294
}

src/tools/rustfmt/tests/source/pin_sugar.rs

+10
Original file line numberDiff line numberDiff line change
@@ -8,3 +8,13 @@ fn g<'a>(x: & 'a pin const i32) {}
88
fn h<'a>(x: & 'a pin
99
mut i32) {}
1010
fn i(x: &pin mut i32) {}
11+
12+
fn borrows() {
13+
let mut foo = 0_i32;
14+
let x: Pin<&mut _> = & pin
15+
mut foo;
16+
17+
let x: Pin<&_> = &
18+
pin const
19+
foo;
20+
}

src/tools/rustfmt/tests/target/pin_sugar.rs

+7
Original file line numberDiff line numberDiff line change
@@ -7,3 +7,10 @@ fn f(x: &pin const i32) {}
77
fn g<'a>(x: &'a pin const i32) {}
88
fn h<'a>(x: &'a pin mut i32) {}
99
fn i(x: &pin mut i32) {}
10+
11+
fn borrows() {
12+
let mut foo = 0_i32;
13+
let x: Pin<&mut _> = &pin mut foo;
14+
15+
let x: Pin<&_> = &pin const foo;
16+
}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,59 @@
1+
#![feature(pin_ergonomics)]
2+
#![allow(dead_code, incomplete_features)]
3+
4+
// Makes sure `&pin mut place` and `&pin const place` cannot violate the mut-xor-share rules.
5+
6+
use std::pin::Pin;
7+
8+
struct Foo;
9+
10+
fn foo_mut(_: &mut Foo) {
11+
}
12+
13+
fn foo_ref(_: &Foo) {
14+
}
15+
16+
fn foo_pin_mut(_: Pin<&mut Foo>) {
17+
}
18+
19+
fn foo_pin_ref(_: Pin<&Foo>) {
20+
}
21+
22+
fn bar() {
23+
let foo = Foo;
24+
foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable
25+
26+
let mut foo = Foo;
27+
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
32+
33+
foo_pin_mut(x);
34+
35+
let mut foo = Foo;
36+
let x = &pin const foo;
37+
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
40+
foo_mut(&mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable
41+
42+
foo_pin_ref(x);
43+
44+
let mut foo = Foo;
45+
let x = &mut foo;
46+
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
48+
49+
foo_mut(x);
50+
51+
let mut foo = Foo;
52+
let x = &foo;
53+
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
55+
56+
foo_ref(x);
57+
}
58+
59+
fn main() {}
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,121 @@
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
8+
|
9+
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+
|
15+
LL | let x = &pin mut foo;
16+
| ------------ mutable borrow occurs here
17+
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
25+
|
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
31+
...
32+
LL | foo_pin_mut(x);
33+
| - first borrow later used here
34+
35+
error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
36+
--> $DIR/borrow-mut-xor-share.rs:30:13
37+
|
38+
LL | let x = &pin mut foo;
39+
| ------------ mutable borrow occurs here
40+
...
41+
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
49+
|
50+
LL | let x = &pin mut foo;
51+
| ------------ first mutable borrow occurs here
52+
...
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
58+
59+
error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
60+
--> $DIR/borrow-mut-xor-share.rs:38:17
61+
|
62+
LL | let x = &pin const foo;
63+
| -------------- immutable borrow occurs here
64+
LL | foo_pin_ref(&pin const foo); // ok
65+
LL | foo_pin_mut(&pin mut foo);
66+
| ^^^^^^^^^^^^ mutable borrow occurs here
67+
...
68+
LL | foo_pin_ref(x);
69+
| - immutable borrow later used here
70+
71+
error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
72+
--> $DIR/borrow-mut-xor-share.rs:40:13
73+
|
74+
LL | let x = &pin const foo;
75+
| -------------- immutable borrow occurs here
76+
...
77+
LL | foo_mut(&mut foo);
78+
| ^^^^^^^^ mutable borrow occurs here
79+
LL |
80+
LL | foo_pin_ref(x);
81+
| - immutable borrow later used here
82+
83+
error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
84+
--> $DIR/borrow-mut-xor-share.rs:46:17
85+
|
86+
LL | let x = &mut foo;
87+
| -------- mutable borrow occurs here
88+
LL | foo_pin_ref(&pin const foo);
89+
| ^^^^^^^^^^^^^^ immutable borrow occurs here
90+
...
91+
LL | foo_mut(x);
92+
| - mutable borrow later used here
93+
94+
error[E0499]: cannot borrow `foo` as mutable more than once at a time
95+
--> $DIR/borrow-mut-xor-share.rs:47:17
96+
|
97+
LL | let x = &mut foo;
98+
| -------- first mutable borrow occurs here
99+
LL | foo_pin_ref(&pin const foo);
100+
LL | foo_pin_mut(&pin mut foo);
101+
| ^^^^^^^^^^^^ second mutable borrow occurs here
102+
LL |
103+
LL | foo_mut(x);
104+
| - first borrow later used here
105+
106+
error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
107+
--> $DIR/borrow-mut-xor-share.rs:54:17
108+
|
109+
LL | let x = &foo;
110+
| ---- immutable borrow occurs here
111+
LL | foo_pin_ref(&pin const foo); // ok
112+
LL | foo_pin_mut(&pin mut foo);
113+
| ^^^^^^^^^^^^ mutable borrow occurs here
114+
LL |
115+
LL | foo_ref(x);
116+
| - immutable borrow later used here
117+
118+
error: aborting due to 10 previous errors
119+
120+
Some errors have detailed explanations: E0499, E0502, E0596.
121+
For more information about an error, try `rustc --explain E0499`.
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
//@ check-pass
2+
3+
#![feature(pin_ergonomics)]
4+
#![allow(dead_code, incomplete_features)]
5+
6+
// 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)`.
8+
9+
use std::pin::Pin;
10+
11+
struct Foo;
12+
13+
fn foo(_: Pin<&mut Foo>) {
14+
}
15+
16+
fn foo_const(_: Pin<&Foo>) {
17+
}
18+
19+
fn bar() {
20+
let mut x: Pin<&mut _> = &pin mut Foo;
21+
foo(x.as_mut());
22+
foo(x.as_mut());
23+
foo_const(x);
24+
25+
let x: Pin<&_> = &pin const Foo;
26+
27+
foo_const(x);
28+
foo_const(x);
29+
}
30+
31+
fn main() {}

0 commit comments

Comments
 (0)