Skip to content

Commit 02e9952

Browse files
Rollup merge of rust-lang#135731 - frank-king:feature/pin-borrow, r=eholk,traviscross
Implement parsing of pinned borrows This PR implements part of rust-lang#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 3de5b08 + afdb54a commit 02e9952

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+
}

0 commit comments

Comments
 (0)