Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit e57789f

Browse files
committedJan 20, 2025
Implement pinned borrows
1 parent 73c0ae6 commit e57789f

File tree

15 files changed

+334
-10
lines changed

15 files changed

+334
-10
lines changed
 

‎compiler/rustc_ast/src/ast.rs

+4
Original file line numberDiff line numberDiff line change
@@ -864,6 +864,10 @@ pub enum BorrowKind {
864864
/// The resulting type is either `*const T` or `*mut T`
865865
/// where `T = typeof($expr)`.
866866
Raw,
867+
/// A pinned borrow, `&pin const $expr` or `&pin mut $expr`.
868+
/// The resulting type is either `Pin<&'a T>` or `Pin<&'a mut T>`
869+
/// where `T = typeof($expr)` and `'a` is some lifetime.
870+
Pin,
867871
}
868872

869873
#[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
@@ -340,6 +340,10 @@ impl<'a> State<'a> {
340340
self.word_nbsp("raw");
341341
self.print_mutability(mutability, true);
342342
}
343+
ast::BorrowKind::Pin => {
344+
self.word_nbsp("pin");
345+
self.print_mutability(mutability, true);
346+
}
343347
}
344348
self.print_expr_cond_paren(
345349
expr,

‎compiler/rustc_const_eval/src/check_consts/ops.rs

+7-5
Original file line numberDiff line numberDiff line change
@@ -596,11 +596,13 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
596596
kind: ccx.const_kind(),
597597
teach: ccx.tcx.sess.teach(E0764),
598598
}),
599-
hir::BorrowKind::Ref => ccx.dcx().create_err(errors::MutableRefEscaping {
600-
span,
601-
kind: ccx.const_kind(),
602-
teach: ccx.tcx.sess.teach(E0764),
603-
}),
599+
hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
600+
ccx.dcx().create_err(errors::MutableRefEscaping {
601+
span,
602+
kind: ccx.const_kind(),
603+
teach: ccx.tcx.sess.teach(E0764),
604+
})
605+
}
604606
}
605607
}
606608
}

‎compiler/rustc_hir_pretty/src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -1338,6 +1338,10 @@ impl<'a> State<'a> {
13381338
self.word_nbsp("raw");
13391339
self.print_mutability(mutability, true);
13401340
}
1341+
hir::BorrowKind::Pin => {
1342+
self.word_nbsp("pin");
1343+
self.print_mutability(mutability, true);
1344+
}
13411345
}
13421346
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Prefix);
13431347
}

‎compiler/rustc_hir_typeck/src/expr.rs

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

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

+25
Original file line numberDiff line numberDiff line change
@@ -474,6 +474,31 @@ impl<'tcx> Cx<'tcx> {
474474
ExprKind::RawBorrow { mutability, arg: self.mirror_expr(arg) }
475475
}
476476

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

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

‎compiler/rustc_parse/src/parser/expr.rs

+4
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,10 @@ impl<'a> Parser<'a> {
871871
assert!(found_raw);
872872
let mutability = self.parse_const_or_mut().unwrap();
873873
(ast::BorrowKind::Raw, mutability)
874+
} else if let Some((ast::Pinnedness::Pinned, mutbl)) = self.parse_pin_and_mut() {
875+
// `pin [ const | mut ]`.
876+
// `pin` has been gated in `self.parse_pin_and_mut()` so we don't need to gate it here.
877+
(ast::BorrowKind::Pin, mutbl)
874878
} else {
875879
// `mut?`
876880
(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() {}

‎tests/ui/feature-gates/feature-gate-pin_ergonomics.rs

+16
Original file line numberDiff line numberDiff line change
@@ -13,6 +13,10 @@ fn foo(x: Pin<&mut Foo>) {
1313
let _y: &pin mut Foo = x; //~ ERROR pinned reference syntax is experimental
1414
}
1515

16+
fn foo_const(x: Pin<&Foo>) {
17+
let _y: &pin const Foo = x; //~ ERROR pinned reference syntax is experimental
18+
}
19+
1620
fn foo_sugar(_: &pin mut Foo) {} //~ ERROR pinned reference syntax is experimental
1721

1822
fn bar(x: Pin<&mut Foo>) {
@@ -27,4 +31,16 @@ fn baz(mut x: Pin<&mut Foo>) {
2731

2832
fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental
2933

34+
fn borrows() {
35+
let mut x: Pin<&mut _> = &pin mut Foo; //~ ERROR pinned reference syntax is experimental
36+
foo(x.as_mut());
37+
foo(x.as_mut());
38+
foo_const(x.as_ref());
39+
40+
let x: Pin<&_> = &pin const Foo; //~ ERROR pinned reference syntax is experimental
41+
42+
foo_const(x);
43+
foo_const(x);
44+
}
45+
3046
fn main() {}
There was a problem loading the remainder of the diff.

0 commit comments

Comments
 (0)
Failed to load comments.