Skip to content

Commit b94ce9f

Browse files
authored
Unrolled build for #135731
Rollup merge of #135731 - frank-king:feature/pin-borrow, r=eholk,traviscross Implement parsing of pinned borrows This PR implements part of #130494. EDIT: It introduces `&pin mut $place` and `&pin const $place` as sugars for `std::pin::pin!($place)` and its shared reference equivalent, except that `$place` will not be moved when borrowing. The borrow check will be in charge of enforcing places cannot be moved or mutably borrowed since being pinned till dropped. ### Implementation steps: - [x] parse the `&pin mut $place` and `&pin const $place` syntaxes - [ ] borrowck of `&pin mut|const` - [ ] support autoref of `&pin mut|const` when needed
2 parents 2c2bb99 + afdb54a commit b94ce9f

33 files changed

+839
-18
lines changed

compiler/rustc_ast/src/ast.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -904,6 +904,10 @@ pub enum BorrowKind {
904904
/// The resulting type is either `*const T` or `*mut T`
905905
/// where `T = typeof($expr)`.
906906
Raw,
907+
/// A pinned borrow, `&pin const $expr` or `&pin mut $expr`.
908+
/// The resulting type is either `Pin<&'a T>` or `Pin<&'a mut T>`
909+
/// where `T = typeof($expr)` and `'a` is some lifetime.
910+
Pin,
907911
}
908912

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

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -357,6 +357,10 @@ impl<'a> State<'a> {
357357
self.word_nbsp("raw");
358358
self.print_mutability(mutability, true);
359359
}
360+
ast::BorrowKind::Pin => {
361+
self.word_nbsp("pin");
362+
self.print_mutability(mutability, true);
363+
}
360364
}
361365
self.print_expr_cond_paren(
362366
expr,

compiler/rustc_const_eval/src/check_consts/ops.rs

Lines changed: 7 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -600,11 +600,13 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
600600
kind: ccx.const_kind(),
601601
teach: ccx.tcx.sess.teach(E0764),
602602
}),
603-
hir::BorrowKind::Ref => ccx.dcx().create_err(errors::MutableRefEscaping {
604-
span,
605-
kind: ccx.const_kind(),
606-
teach: ccx.tcx.sess.teach(E0764),
607-
}),
603+
hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
604+
ccx.dcx().create_err(errors::MutableRefEscaping {
605+
span,
606+
kind: ccx.const_kind(),
607+
teach: ccx.tcx.sess.teach(E0764),
608+
})
609+
}
608610
}
609611
}
610612
}

compiler/rustc_hir_pretty/src/lib.rs

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1335,6 +1335,10 @@ impl<'a> State<'a> {
13351335
self.word_nbsp("raw");
13361336
self.print_mutability(mutability, true);
13371337
}
1338+
hir::BorrowKind::Pin => {
1339+
self.word_nbsp("pin");
1340+
self.print_mutability(mutability, true);
1341+
}
13381342
}
13391343
self.print_expr_cond_paren(expr, self.precedence(expr) < ExprPrecedence::Prefix);
13401344
}

compiler/rustc_hir_typeck/src/expr.rs

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -690,7 +690,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
690690
self.check_named_place_expr(oprnd);
691691
Ty::new_ptr(self.tcx, ty, mutbl)
692692
}
693-
hir::BorrowKind::Ref => {
693+
hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
694694
// Note: at this point, we cannot say what the best lifetime
695695
// is to use for resulting pointer. We want to use the
696696
// shortest lifetime possible so as to avoid spurious borrowck
@@ -706,7 +706,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
706706
// whose address was taken can actually be made to live as long
707707
// as it needs to live.
708708
let region = self.next_region_var(infer::BorrowRegion(expr.span));
709-
Ty::new_ref(self.tcx, region, ty, mutbl)
709+
match kind {
710+
hir::BorrowKind::Ref => Ty::new_ref(self.tcx, region, ty, mutbl),
711+
hir::BorrowKind::Pin => Ty::new_pinned_ref(self.tcx, region, ty, mutbl),
712+
_ => unreachable!(),
713+
}
710714
}
711715
}
712716
}

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

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -479,6 +479,55 @@ impl<'tcx> ThirBuildCx<'tcx> {
479479
ExprKind::RawBorrow { mutability, arg: self.mirror_expr(arg) }
480480
}
481481

482+
// Make `&pin mut $expr` and `&pin const $expr` into
483+
// `Pin { __pointer: &mut { $expr } }` and `Pin { __pointer: &$expr }`.
484+
hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg_expr) => match expr_ty.kind() {
485+
&ty::Adt(adt_def, args) if tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin) => {
486+
let ty = args.type_at(0);
487+
let arg_ty = self.typeck_results.expr_ty(arg_expr);
488+
let mut arg = self.mirror_expr(arg_expr);
489+
// For `&pin mut $place` where `$place` is not `Unpin`, move the place
490+
// `$place` to ensure it will not be used afterwards.
491+
if mutbl.is_mut() && !arg_ty.is_unpin(self.tcx, self.typing_env) {
492+
let block = self.thir.blocks.push(Block {
493+
targeted_by_break: false,
494+
region_scope: region::Scope {
495+
local_id: arg_expr.hir_id.local_id,
496+
data: region::ScopeData::Node,
497+
},
498+
span: arg_expr.span,
499+
stmts: Box::new([]),
500+
expr: Some(arg),
501+
safety_mode: BlockSafety::Safe,
502+
});
503+
let (temp_lifetime, backwards_incompatible) = self
504+
.rvalue_scopes
505+
.temporary_scope(self.region_scope_tree, arg_expr.hir_id.local_id);
506+
arg = self.thir.exprs.push(Expr {
507+
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
508+
ty: arg_ty,
509+
span: arg_expr.span,
510+
kind: ExprKind::Block { block },
511+
});
512+
}
513+
let expr = self.thir.exprs.push(Expr {
514+
temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
515+
ty,
516+
span: expr.span,
517+
kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg },
518+
});
519+
ExprKind::Adt(Box::new(AdtExpr {
520+
adt_def,
521+
variant_index: FIRST_VARIANT,
522+
args,
523+
fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
524+
user_ty: None,
525+
base: AdtExprBase::None,
526+
}))
527+
}
528+
_ => span_bug!(expr.span, "unexpected type for pinned borrow: {:?}", expr_ty),
529+
},
530+
482531
hir::ExprKind::Block(blk, _) => ExprKind::Block { block: self.mirror_block(blk) },
483532

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

compiler/rustc_parse/src/parser/expr.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -847,14 +847,19 @@ impl<'a> Parser<'a> {
847847
self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
848848
}
849849

850-
/// Parse `mut?` or `raw [ const | mut ]`.
850+
/// Parse `mut?` or `[ raw | pin ] [ const | mut ]`.
851851
fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
852852
if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {
853853
// `raw [ const | mut ]`.
854854
let found_raw = self.eat_keyword(exp!(Raw));
855855
assert!(found_raw);
856856
let mutability = self.parse_const_or_mut().unwrap();
857857
(ast::BorrowKind::Raw, mutability)
858+
} else if let Some((ast::Pinnedness::Pinned, mutbl)) = self.parse_pin_and_mut() {
859+
// `pin [ const | mut ]`.
860+
// `pin` has been gated in `self.parse_pin_and_mut()` so we don't
861+
// need to gate it here.
862+
(ast::BorrowKind::Pin, mutbl)
858863
} else {
859864
// `mut?`
860865
(ast::BorrowKind::Ref, self.parse_mutability())

src/tools/rustfmt/src/expr.rs

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2289,8 +2289,10 @@ fn rewrite_expr_addrof(
22892289
) -> RewriteResult {
22902290
let operator_str = match (mutability, borrow_kind) {
22912291
(ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
2292+
(ast::Mutability::Not, ast::BorrowKind::Pin) => "&pin const ",
22922293
(ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
22932294
(ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
2295+
(ast::Mutability::Mut, ast::BorrowKind::Pin) => "&pin mut ",
22942296
(ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
22952297
};
22962298
rewrite_unary_prefix(context, operator_str, expr, shape)

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

Lines changed: 10 additions & 0 deletions
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

Lines changed: 7 additions & 0 deletions
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

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
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+
#[prelude_import]
8+
use ::std::prelude::rust_2015::*;
9+
#[macro_use]
10+
extern crate std;
11+
12+
use std::pin::Pin;
13+
14+
struct Foo;
15+
16+
impl Foo {
17+
fn baz(&mut self) { }
18+
19+
fn baz_const(&self) { }
20+
21+
fn baz_lt<'a>(&mut self) { }
22+
23+
fn baz_const_lt(&self) { }
24+
}
25+
26+
fn foo(_: Pin<&'_ mut Foo>) { }
27+
fn foo_lt<'a>(_: Pin<&'a mut Foo>) { }
28+
29+
fn foo_const(_: Pin<&'_ Foo>) { }
30+
fn foo_const_lt(_: Pin<&'_ Foo>) { }
31+
32+
fn bar() {
33+
let mut x: Pin<&mut _> = &pin mut Foo;
34+
foo(x.as_mut());
35+
foo(x.as_mut());
36+
foo_const(x);
37+
38+
let x: Pin<&_> = &pin const Foo;
39+
40+
foo_const(x);
41+
foo_const(x);
42+
}
43+
44+
fn main() { }

tests/pretty/pin-ergonomics-hir.rs

Lines changed: 40 additions & 0 deletions
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

Lines changed: 13 additions & 0 deletions
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,15 @@ 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+
foo_const(x);
34+
foo_const(x);
35+
}
36+
2437
fn main() {}

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

Lines changed: 28 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -17,6 +17,10 @@ fn foo(mut x: Pin<&mut Foo>) {
1717
let _y: &pin mut Foo = x; //~ ERROR pinned reference syntax is experimental
1818
}
1919

20+
fn foo_const(x: Pin<&Foo>) {
21+
let _y: &pin const Foo = x; //~ ERROR pinned reference syntax is experimental
22+
}
23+
2024
fn foo_sugar(_: &pin mut Foo) {} //~ ERROR pinned reference syntax is experimental
2125

2226
fn bar(x: Pin<&mut Foo>) {
@@ -31,6 +35,18 @@ fn baz(mut x: Pin<&mut Foo>) {
3135

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

38+
fn borrows() {
39+
let mut x: Pin<&mut _> = &pin mut Foo; //~ ERROR pinned reference syntax is experimental
40+
foo(x.as_mut());
41+
foo(x.as_mut());
42+
foo_const(x.as_ref());
43+
44+
let x: Pin<&_> = &pin const Foo; //~ ERROR pinned reference syntax is experimental
45+
46+
foo_const(x);
47+
foo_const(x);
48+
}
49+
3450
#[cfg(any())]
3551
mod not_compiled {
3652
use std::pin::Pin;
@@ -63,6 +79,18 @@ mod not_compiled {
6379
}
6480

6581
fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental
82+
83+
fn borrows() {
84+
let mut x: Pin<&mut _> = &pin mut Foo; //~ ERROR pinned reference syntax is experimental
85+
foo(x.as_mut());
86+
foo(x.as_mut());
87+
foo_const(x.as_ref());
88+
89+
let x: Pin<&_> = &pin const Foo; //~ ERROR pinned reference syntax is experimental
90+
91+
foo_const(x);
92+
foo_const(x);
93+
}
6694
}
6795

6896
fn main() {}

0 commit comments

Comments
 (0)