Skip to content

Commit b2f9af8

Browse files
committed
Implement pinned borrows, part of pin_ergonomics
1 parent 59a9b9e commit b2f9af8

File tree

18 files changed

+471
-18
lines changed

18 files changed

+471
-18
lines changed

compiler/rustc_ast/src/ast.rs

+4
Original file line numberDiff line numberDiff line change
@@ -877,6 +877,10 @@ pub enum BorrowKind {
877877
/// The resulting type is either `*const T` or `*mut T`
878878
/// where `T = typeof($expr)`.
879879
Raw,
880+
/// A pinned borrow, `&pin const $expr` or `&pin mut $expr`.
881+
/// The resulting type is either `Pin<&'a T>` or `Pin<&'a mut T>`
882+
/// where `T = typeof($expr)` and `'a` is some lifetime.
883+
Pin,
880884
}
881885

882886
#[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
@@ -1417,6 +1417,10 @@ impl<'a> State<'a> {
14171417
self.word_nbsp("raw");
14181418
self.print_mutability(mutability, true);
14191419
}
1420+
hir::BorrowKind::Pin => {
1421+
self.word_nbsp("pin");
1422+
self.print_mutability(mutability, true);
1423+
}
14201424
}
14211425
self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Prefix);
14221426
}

compiler/rustc_hir_typeck/src/expr.rs

+6-2
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
670670
self.check_named_place_expr(oprnd);
671671
Ty::new_ptr(self.tcx, ty, mutbl)
672672
}
673-
hir::BorrowKind::Ref => {
673+
hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
674674
// Note: at this point, we cannot say what the best lifetime
675675
// is to use for resulting pointer. We want to use the
676676
// shortest lifetime possible so as to avoid spurious borrowck
@@ -686,7 +686,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
686686
// whose address was taken can actually be made to live as long
687687
// as it needs to live.
688688
let region = self.next_region_var(infer::BorrowRegion(expr.span));
689-
Ty::new_ref(self.tcx, region, ty, mutbl)
689+
match kind {
690+
hir::BorrowKind::Ref => Ty::new_ref(self.tcx, region, ty, mutbl),
691+
hir::BorrowKind::Pin => Ty::new_pinned_ref(self.tcx, region, ty, mutbl),
692+
_ => unreachable!(),
693+
}
690694
}
691695
}
692696
}

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
476+
// `Pin { __pointer: &mut $expr }` 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

+6-1
Original file line numberDiff line numberDiff line change
@@ -828,14 +828,19 @@ impl<'a> Parser<'a> {
828828
self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
829829
}
830830

831-
/// Parse `mut?` or `raw [ const | mut ]`.
831+
/// Parse `mut?` or `[ raw | pin ] [ const | mut ]`.
832832
fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
833833
if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {
834834
// `raw [ const | mut ]`.
835835
let found_raw = self.eat_keyword(exp!(Raw));
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
842+
// need to gate it here.
843+
(ast::BorrowKind::Pin, mutbl)
839844
} else {
840845
// `mut?`
841846
(ast::BorrowKind::Ref, self.parse_mutability())

src/tools/rustfmt/src/expr.rs

+2
Original file line numberDiff line numberDiff line change
@@ -2284,8 +2284,10 @@ fn rewrite_expr_addrof(
22842284
) -> RewriteResult {
22852285
let operator_str = match (mutability, borrow_kind) {
22862286
(ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
2287+
(ast::Mutability::Not, ast::BorrowKind::Pin) => "&pin const ",
22872288
(ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
22882289
(ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
2290+
(ast::Mutability::Mut, ast::BorrowKind::Pin) => "&pin mut ",
22892291
(ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
22902292
};
22912293
rewrite_unary_prefix(context, operator_str, expr, shape)

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

+10
Original file line numberDiff line numberDiff line change
@@ -18,3 +18,13 @@ impl Foo {
1818
mut self) {}
1919
fn i(&pin mut self) {}
2020
}
21+
22+
fn borrows() {
23+
let mut foo = 0_i32;
24+
let x: Pin<&mut _> = & pin
25+
mut foo;
26+
27+
let x: Pin<&_> = &
28+
pin const
29+
foo;
30+
}

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

+7
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,10 @@ impl Foo {
1616
fn h<'a>(&'a pin mut self) {}
1717
fn i(&pin mut self) {}
1818
}
19+
20+
fn borrows() {
21+
let mut foo = 0_i32;
22+
let x: Pin<&mut _> = &pin mut foo;
23+
24+
let x: Pin<&_> = &pin const foo;
25+
}

tests/pretty/pin-ergonomics-hir.pp

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
//@ pretty-compare-only
2+
//@ pretty-mode:hir
3+
//@ pp-exact:pin-ergonomics-hir.pp
4+
5+
#![feature(pin_ergonomics)]#![allow(dead_code, incomplete_features)]
6+
#[prelude_import]
7+
use ::std::prelude::rust_2015::*;
8+
#[macro_use]
9+
extern crate std;
10+
11+
use std::pin::Pin;
12+
13+
struct Foo;
14+
15+
impl Foo {
16+
fn baz(&mut self) { }
17+
18+
fn baz_const(&self) { }
19+
20+
fn baz_lt<'a>(&mut self) { }
21+
22+
fn baz_const_lt(&self) { }
23+
}
24+
25+
fn foo(_: Pin<&'_ mut Foo>) { }
26+
fn foo_lt<'a>(_: Pin<&'a mut Foo>) { }
27+
28+
fn foo_const(_: Pin<&'_ Foo>) { }
29+
fn foo_const_lt(_: Pin<&'_ Foo>) { }
30+
31+
fn bar() {
32+
let mut x: Pin<&mut _> = &pin mut Foo;
33+
foo(x.as_mut());
34+
foo(x.as_mut());
35+
foo_const(x);
36+
37+
let x: Pin<&_> = &pin const Foo;
38+
39+
foo_const(x);
40+
foo_const(x);
41+
}
42+
43+
fn main() { }

tests/pretty/pin-ergonomics-hir.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
//@ pretty-compare-only
2+
//@ pretty-mode:hir
3+
//@ pp-exact:pin-ergonomics-hir.pp
4+
5+
#![feature(pin_ergonomics)]
6+
#![allow(dead_code, incomplete_features)]
7+
8+
use std::pin::Pin;
9+
10+
struct Foo;
11+
12+
impl Foo {
13+
fn baz(&mut self) { }
14+
15+
fn baz_const(&self) { }
16+
17+
fn baz_lt<'a>(&mut self) { }
18+
19+
fn baz_const_lt(&self) { }
20+
}
21+
22+
fn foo(_: Pin<&'_ mut Foo>) { }
23+
fn foo_lt<'a>(_: Pin<&'a mut Foo>) { }
24+
25+
fn foo_const(_: Pin<&'_ Foo>) { }
26+
fn foo_const_lt(_: Pin<&'_ Foo>) { }
27+
28+
fn bar() {
29+
let mut x: Pin<&mut _> = &pin mut Foo;
30+
foo(x.as_mut());
31+
foo(x.as_mut());
32+
foo_const(x);
33+
34+
let x: Pin<&_> = &pin const Foo;
35+
36+
foo_const(x);
37+
foo_const(x);
38+
}
39+
40+
fn main() { }

tests/pretty/pin-ergonomics.rs

+14
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,8 @@
33
#![feature(pin_ergonomics)]
44
#![allow(dead_code, incomplete_features)]
55

6+
use std::pin::Pin;
7+
68
struct Foo;
79

810
impl Foo {
@@ -21,4 +23,16 @@ fn foo_lt<'a>(_: &'a pin mut Foo) {}
2123
fn foo_const(_: &pin const Foo) {}
2224
fn foo_const_lt(_: &'_ pin const Foo) {}
2325

26+
fn bar() {
27+
let mut x: Pin<&mut _> = &pin mut Foo;
28+
foo(x.as_mut());
29+
foo(x.as_mut());
30+
foo_const(x);
31+
32+
let x: Pin<&_> = &pin const Foo;
33+
34+
foo_const(x);
35+
foo_const(x);
36+
}
37+
2438
fn main() {}
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() {}

0 commit comments

Comments
 (0)