about summary refs log tree commit diff
diff options
context:
space:
mode:
authorFrank King <frankking1729@gmail.com>2025-01-19 22:01:11 +0800
committerFrank King <frankking1729@gmail.com>2025-06-15 10:21:29 +0800
commite627f88f88de85cc52ff1c99a076909084806c98 (patch)
tree0f53bd1e6bef6c79ada367f0a6ca8c7ac6eb2f93
parent49a8ba06848fa8f282fe9055b4178350970bb0ce (diff)
downloadrust-e627f88f88de85cc52ff1c99a076909084806c98.tar.gz
rust-e627f88f88de85cc52ff1c99a076909084806c98.zip
Implement pinned borrows, part of `pin_ergonomics`
-rw-r--r--compiler/rustc_ast/src/ast.rs4
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state/expr.rs4
-rw-r--r--compiler/rustc_const_eval/src/check_consts/ops.rs12
-rw-r--r--compiler/rustc_hir_pretty/src/lib.rs4
-rw-r--r--compiler/rustc_hir_typeck/src/expr.rs8
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs25
-rw-r--r--compiler/rustc_parse/src/parser/expr.rs7
-rw-r--r--src/tools/rustfmt/src/expr.rs2
-rw-r--r--src/tools/rustfmt/tests/source/pin_sugar.rs10
-rw-r--r--src/tools/rustfmt/tests/target/pin_sugar.rs7
-rw-r--r--tests/pretty/pin-ergonomics-hir.pp43
-rw-r--r--tests/pretty/pin-ergonomics-hir.rs40
-rw-r--r--tests/pretty/pin-ergonomics.rs14
-rw-r--r--tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.rs59
-rw-r--r--tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.stderr121
-rw-r--r--tests/ui/async-await/pin-ergonomics/borrow.rs31
-rw-r--r--tests/ui/feature-gates/feature-gate-pin_ergonomics.rs28
-rw-r--r--tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr70
18 files changed, 471 insertions, 18 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index 6b51cbd7fbe..40f0ac6dea3 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -898,6 +898,10 @@ pub enum BorrowKind {
     /// The resulting type is either `*const T` or `*mut T`
     /// where `T = typeof($expr)`.
     Raw,
+    /// A pinned borrow, `&pin const $expr` or `&pin mut $expr`.
+    /// The resulting type is either `Pin<&'a T>` or `Pin<&'a mut T>`
+    /// where `T = typeof($expr)` and `'a` is some lifetime.
+    Pin,
 }
 
 #[derive(Clone, Copy, Debug, PartialEq, Encodable, Decodable, HashStable_Generic)]
diff --git a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
index ee49246a4bb..32c14e5fe15 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state/expr.rs
@@ -357,6 +357,10 @@ impl<'a> State<'a> {
                 self.word_nbsp("raw");
                 self.print_mutability(mutability, true);
             }
+            ast::BorrowKind::Pin => {
+                self.word_nbsp("pin");
+                self.print_mutability(mutability, true);
+            }
         }
         self.print_expr_cond_paren(
             expr,
diff --git a/compiler/rustc_const_eval/src/check_consts/ops.rs b/compiler/rustc_const_eval/src/check_consts/ops.rs
index 9c30dbff99e..1bba3fe7ec3 100644
--- a/compiler/rustc_const_eval/src/check_consts/ops.rs
+++ b/compiler/rustc_const_eval/src/check_consts/ops.rs
@@ -616,11 +616,13 @@ impl<'tcx> NonConstOp<'tcx> for EscapingMutBorrow {
                 kind: ccx.const_kind(),
                 teach: ccx.tcx.sess.teach(E0764),
             }),
-            hir::BorrowKind::Ref => ccx.dcx().create_err(errors::MutableRefEscaping {
-                span,
-                kind: ccx.const_kind(),
-                teach: ccx.tcx.sess.teach(E0764),
-            }),
+            hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
+                ccx.dcx().create_err(errors::MutableRefEscaping {
+                    span,
+                    kind: ccx.const_kind(),
+                    teach: ccx.tcx.sess.teach(E0764),
+                })
+            }
         }
     }
 }
diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs
index b23b3125c59..23d37facaa3 100644
--- a/compiler/rustc_hir_pretty/src/lib.rs
+++ b/compiler/rustc_hir_pretty/src/lib.rs
@@ -1339,6 +1339,10 @@ impl<'a> State<'a> {
                 self.word_nbsp("raw");
                 self.print_mutability(mutability, true);
             }
+            hir::BorrowKind::Pin => {
+                self.word_nbsp("pin");
+                self.print_mutability(mutability, true);
+            }
         }
         self.print_expr_cond_paren(expr, expr.precedence() < ExprPrecedence::Prefix);
     }
diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs
index 30bf557dc93..b87907f8460 100644
--- a/compiler/rustc_hir_typeck/src/expr.rs
+++ b/compiler/rustc_hir_typeck/src/expr.rs
@@ -664,7 +664,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 self.check_named_place_expr(oprnd);
                 Ty::new_ptr(self.tcx, ty, mutbl)
             }
-            hir::BorrowKind::Ref => {
+            hir::BorrowKind::Ref | hir::BorrowKind::Pin => {
                 // Note: at this point, we cannot say what the best lifetime
                 // is to use for resulting pointer. We want to use the
                 // shortest lifetime possible so as to avoid spurious borrowck
@@ -680,7 +680,11 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
                 // whose address was taken can actually be made to live as long
                 // as it needs to live.
                 let region = self.next_region_var(infer::BorrowRegion(expr.span));
-                Ty::new_ref(self.tcx, region, ty, mutbl)
+                match kind {
+                    hir::BorrowKind::Ref => Ty::new_ref(self.tcx, region, ty, mutbl),
+                    hir::BorrowKind::Pin => Ty::new_pinned_ref(self.tcx, region, ty, mutbl),
+                    _ => unreachable!(),
+                }
             }
         }
     }
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 3baeccf6409..52de0395ab6 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -479,6 +479,31 @@ impl<'tcx> ThirBuildCx<'tcx> {
                 ExprKind::RawBorrow { mutability, arg: self.mirror_expr(arg) }
             }
 
+            // Make `&pin mut $expr` and `&pin const $expr` into
+            // `Pin { __pointer: &mut $expr }` and `Pin { __pointer: &$expr }`.
+            hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg) => match expr_ty.kind() {
+                &ty::Adt(adt_def, args)
+                    if tcx.is_lang_item(adt_def.did(), rustc_hir::LangItem::Pin) =>
+                {
+                    let arg = self.mirror_expr(arg);
+                    let expr = self.thir.exprs.push(Expr {
+                        temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+                        ty: args.type_at(0),
+                        span: expr.span,
+                        kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg },
+                    });
+                    ExprKind::Adt(Box::new(AdtExpr {
+                        adt_def,
+                        variant_index: FIRST_VARIANT,
+                        args,
+                        fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
+                        user_ty: None,
+                        base: AdtExprBase::None,
+                    }))
+                }
+                _ => span_bug!(expr.span, "unexpected type for pinned borrow: {:?}", expr_ty),
+            },
+
             hir::ExprKind::Block(blk, _) => ExprKind::Block { block: self.mirror_block(blk) },
 
             hir::ExprKind::Assign(lhs, rhs, _) => {
diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs
index 93489aa8ee9..b64b50cf187 100644
--- a/compiler/rustc_parse/src/parser/expr.rs
+++ b/compiler/rustc_parse/src/parser/expr.rs
@@ -847,7 +847,7 @@ impl<'a> Parser<'a> {
         self.dcx().emit_err(errors::LifetimeInBorrowExpression { span, lifetime_span: lt_span });
     }
 
-    /// Parse `mut?` or `raw [ const | mut ]`.
+    /// Parse `mut?` or `[ raw | pin ] [ const | mut ]`.
     fn parse_borrow_modifiers(&mut self) -> (ast::BorrowKind, ast::Mutability) {
         if self.check_keyword(exp!(Raw)) && self.look_ahead(1, Token::is_mutability) {
             // `raw [ const | mut ]`.
@@ -855,6 +855,11 @@ impl<'a> Parser<'a> {
             assert!(found_raw);
             let mutability = self.parse_const_or_mut().unwrap();
             (ast::BorrowKind::Raw, mutability)
+        } else if let Some((ast::Pinnedness::Pinned, mutbl)) = self.parse_pin_and_mut() {
+            // `pin [ const | mut ]`.
+            // `pin` has been gated in `self.parse_pin_and_mut()` so we don't
+            // need to gate it here.
+            (ast::BorrowKind::Pin, mutbl)
         } else {
             // `mut?`
             (ast::BorrowKind::Ref, self.parse_mutability())
diff --git a/src/tools/rustfmt/src/expr.rs b/src/tools/rustfmt/src/expr.rs
index be6b483bfff..08aedff2b20 100644
--- a/src/tools/rustfmt/src/expr.rs
+++ b/src/tools/rustfmt/src/expr.rs
@@ -2289,8 +2289,10 @@ fn rewrite_expr_addrof(
 ) -> RewriteResult {
     let operator_str = match (mutability, borrow_kind) {
         (ast::Mutability::Not, ast::BorrowKind::Ref) => "&",
+        (ast::Mutability::Not, ast::BorrowKind::Pin) => "&pin const ",
         (ast::Mutability::Not, ast::BorrowKind::Raw) => "&raw const ",
         (ast::Mutability::Mut, ast::BorrowKind::Ref) => "&mut ",
+        (ast::Mutability::Mut, ast::BorrowKind::Pin) => "&pin mut ",
         (ast::Mutability::Mut, ast::BorrowKind::Raw) => "&raw mut ",
     };
     rewrite_unary_prefix(context, operator_str, expr, shape)
diff --git a/src/tools/rustfmt/tests/source/pin_sugar.rs b/src/tools/rustfmt/tests/source/pin_sugar.rs
index 370dfbc196a..e5b47339b92 100644
--- a/src/tools/rustfmt/tests/source/pin_sugar.rs
+++ b/src/tools/rustfmt/tests/source/pin_sugar.rs
@@ -18,3 +18,13 @@ impl Foo {
 mut self) {}
     fn i(&pin      mut   self) {}
 }
+
+fn borrows() {
+    let mut foo = 0_i32;
+    let x: Pin<&mut _> = & pin 
+    mut    foo;
+
+    let x: Pin<&_> = &
+    pin                const 
+    foo;
+}
diff --git a/src/tools/rustfmt/tests/target/pin_sugar.rs b/src/tools/rustfmt/tests/target/pin_sugar.rs
index 7d04efb1b32..09ad23a5807 100644
--- a/src/tools/rustfmt/tests/target/pin_sugar.rs
+++ b/src/tools/rustfmt/tests/target/pin_sugar.rs
@@ -16,3 +16,10 @@ impl Foo {
     fn h<'a>(&'a pin mut self) {}
     fn i(&pin mut self) {}
 }
+
+fn borrows() {
+    let mut foo = 0_i32;
+    let x: Pin<&mut _> = &pin mut foo;
+
+    let x: Pin<&_> = &pin const foo;
+}
diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp
new file mode 100644
index 00000000000..42405982f92
--- /dev/null
+++ b/tests/pretty/pin-ergonomics-hir.pp
@@ -0,0 +1,43 @@
+//@ pretty-compare-only
+//@ pretty-mode:hir
+//@ pp-exact:pin-ergonomics-hir.pp
+
+#![feature(pin_ergonomics)]#![allow(dead_code, incomplete_features)]
+#[prelude_import]
+use ::std::prelude::rust_2015::*;
+#[macro_use]
+extern crate std;
+
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+    fn baz(&mut self) { }
+
+    fn baz_const(&self) { }
+
+    fn baz_lt<'a>(&mut self) { }
+
+    fn baz_const_lt(&self) { }
+}
+
+fn foo(_: Pin<&'_ mut Foo>) { }
+fn foo_lt<'a>(_: Pin<&'a mut Foo>) { }
+
+fn foo_const(_: Pin<&'_ Foo>) { }
+fn foo_const_lt(_: Pin<&'_ Foo>) { }
+
+fn bar() {
+    let mut x: Pin<&mut _> = &pin mut Foo;
+    foo(x.as_mut());
+    foo(x.as_mut());
+    foo_const(x);
+
+    let x: Pin<&_> = &pin const Foo;
+
+    foo_const(x);
+    foo_const(x);
+}
+
+fn main() { }
diff --git a/tests/pretty/pin-ergonomics-hir.rs b/tests/pretty/pin-ergonomics-hir.rs
new file mode 100644
index 00000000000..5f2158258f0
--- /dev/null
+++ b/tests/pretty/pin-ergonomics-hir.rs
@@ -0,0 +1,40 @@
+//@ pretty-compare-only
+//@ pretty-mode:hir
+//@ pp-exact:pin-ergonomics-hir.pp
+
+#![feature(pin_ergonomics)]
+#![allow(dead_code, incomplete_features)]
+
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+    fn baz(&mut self) { }
+
+    fn baz_const(&self) { }
+
+    fn baz_lt<'a>(&mut self) { }
+
+    fn baz_const_lt(&self) { }
+}
+
+fn foo(_: Pin<&'_ mut Foo>) { }
+fn foo_lt<'a>(_: Pin<&'a mut Foo>) { }
+
+fn foo_const(_: Pin<&'_ Foo>) { }
+fn foo_const_lt(_: Pin<&'_ Foo>) { }
+
+fn bar() {
+    let mut x: Pin<&mut _> = &pin mut Foo;
+    foo(x.as_mut());
+    foo(x.as_mut());
+    foo_const(x);
+
+    let x: Pin<&_> = &pin const Foo;
+
+    foo_const(x);
+    foo_const(x);
+}
+
+fn main() { }
diff --git a/tests/pretty/pin-ergonomics.rs b/tests/pretty/pin-ergonomics.rs
index 47ffc97b118..54a57545c55 100644
--- a/tests/pretty/pin-ergonomics.rs
+++ b/tests/pretty/pin-ergonomics.rs
@@ -3,6 +3,8 @@
 #![feature(pin_ergonomics)]
 #![allow(dead_code, incomplete_features)]
 
+use std::pin::Pin;
+
 struct Foo;
 
 impl Foo {
@@ -21,4 +23,16 @@ fn foo_lt<'a>(_: &'a pin mut Foo) {}
 fn foo_const(_: &pin const Foo) {}
 fn foo_const_lt(_: &'_ pin const Foo) {}
 
+fn bar() {
+    let mut x: Pin<&mut _> = &pin mut Foo;
+    foo(x.as_mut());
+    foo(x.as_mut());
+    foo_const(x);
+
+    let x: Pin<&_> = &pin const Foo;
+
+    foo_const(x);
+    foo_const(x);
+}
+
 fn main() {}
diff --git a/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.rs b/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.rs
new file mode 100644
index 00000000000..c5363eafef5
--- /dev/null
+++ b/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.rs
@@ -0,0 +1,59 @@
+#![feature(pin_ergonomics)]
+#![allow(dead_code, incomplete_features)]
+
+// Makes sure `&pin mut place` and `&pin const place` cannot violate the mut-xor-share rules.
+
+use std::pin::Pin;
+
+struct Foo;
+
+fn foo_mut(_: &mut Foo) {
+}
+
+fn foo_ref(_: &Foo) {
+}
+
+fn foo_pin_mut(_: Pin<&mut Foo>) {
+}
+
+fn foo_pin_ref(_: Pin<&Foo>) {
+}
+
+fn bar() {
+    let foo = Foo;
+    foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable
+
+    let mut foo = Foo;
+    let x = &pin mut foo;
+    foo_pin_ref(&pin const foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
+    foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time
+    foo_ref(&foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
+    foo_mut(&mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time
+
+    foo_pin_mut(x);
+
+    let mut foo = Foo;
+    let x = &pin const foo;
+    foo_pin_ref(&pin const foo); // ok
+    foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable
+    foo_ref(&foo); // ok
+    foo_mut(&mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable
+
+    foo_pin_ref(x);
+
+    let mut foo = Foo;
+    let x = &mut foo;
+    foo_pin_ref(&pin const foo); //~ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
+    foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable more than once at a time
+
+    foo_mut(x);
+
+    let mut foo = Foo;
+    let x = &foo;
+    foo_pin_ref(&pin const foo); // ok
+    foo_pin_mut(&pin mut foo); //~ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable
+
+    foo_ref(x);
+}
+
+fn main() {}
diff --git a/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.stderr b/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.stderr
new file mode 100644
index 00000000000..47d990b2ec9
--- /dev/null
+++ b/tests/ui/async-await/pin-ergonomics/borrow-mut-xor-share.stderr
@@ -0,0 +1,121 @@
+error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable
+  --> $DIR/borrow-mut-xor-share.rs:24:17
+   |
+LL |     foo_pin_mut(&pin mut foo);
+   |                 ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut foo = Foo;
+   |         +++
+
+error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
+  --> $DIR/borrow-mut-xor-share.rs:28:17
+   |
+LL |     let x = &pin mut foo;
+   |             ------------ mutable borrow occurs here
+LL |     foo_pin_ref(&pin const foo);
+   |                 ^^^^^^^^^^^^^^ immutable borrow occurs here
+...
+LL |     foo_pin_mut(x);
+   |                 - mutable borrow later used here
+
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/borrow-mut-xor-share.rs:29:17
+   |
+LL |     let x = &pin mut foo;
+   |             ------------ first mutable borrow occurs here
+LL |     foo_pin_ref(&pin const foo);
+LL |     foo_pin_mut(&pin mut foo);
+   |                 ^^^^^^^^^^^^ second mutable borrow occurs here
+...
+LL |     foo_pin_mut(x);
+   |                 - first borrow later used here
+
+error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
+  --> $DIR/borrow-mut-xor-share.rs:30:13
+   |
+LL |     let x = &pin mut foo;
+   |             ------------ mutable borrow occurs here
+...
+LL |     foo_ref(&foo);
+   |             ^^^^ immutable borrow occurs here
+...
+LL |     foo_pin_mut(x);
+   |                 - mutable borrow later used here
+
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/borrow-mut-xor-share.rs:31:13
+   |
+LL |     let x = &pin mut foo;
+   |             ------------ first mutable borrow occurs here
+...
+LL |     foo_mut(&mut foo);
+   |             ^^^^^^^^ second mutable borrow occurs here
+LL |
+LL |     foo_pin_mut(x);
+   |                 - first borrow later used here
+
+error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
+  --> $DIR/borrow-mut-xor-share.rs:38:17
+   |
+LL |     let x = &pin const foo;
+   |             -------------- immutable borrow occurs here
+LL |     foo_pin_ref(&pin const foo); // ok
+LL |     foo_pin_mut(&pin mut foo);
+   |                 ^^^^^^^^^^^^ mutable borrow occurs here
+...
+LL |     foo_pin_ref(x);
+   |                 - immutable borrow later used here
+
+error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
+  --> $DIR/borrow-mut-xor-share.rs:40:13
+   |
+LL |     let x = &pin const foo;
+   |             -------------- immutable borrow occurs here
+...
+LL |     foo_mut(&mut foo);
+   |             ^^^^^^^^ mutable borrow occurs here
+LL |
+LL |     foo_pin_ref(x);
+   |                 - immutable borrow later used here
+
+error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
+  --> $DIR/borrow-mut-xor-share.rs:46:17
+   |
+LL |     let x = &mut foo;
+   |             -------- mutable borrow occurs here
+LL |     foo_pin_ref(&pin const foo);
+   |                 ^^^^^^^^^^^^^^ immutable borrow occurs here
+...
+LL |     foo_mut(x);
+   |             - mutable borrow later used here
+
+error[E0499]: cannot borrow `foo` as mutable more than once at a time
+  --> $DIR/borrow-mut-xor-share.rs:47:17
+   |
+LL |     let x = &mut foo;
+   |             -------- first mutable borrow occurs here
+LL |     foo_pin_ref(&pin const foo);
+LL |     foo_pin_mut(&pin mut foo);
+   |                 ^^^^^^^^^^^^ second mutable borrow occurs here
+LL |
+LL |     foo_mut(x);
+   |             - first borrow later used here
+
+error[E0502]: cannot borrow `foo` as mutable because it is also borrowed as immutable
+  --> $DIR/borrow-mut-xor-share.rs:54:17
+   |
+LL |     let x = &foo;
+   |             ---- immutable borrow occurs here
+LL |     foo_pin_ref(&pin const foo); // ok
+LL |     foo_pin_mut(&pin mut foo);
+   |                 ^^^^^^^^^^^^ mutable borrow occurs here
+LL |
+LL |     foo_ref(x);
+   |             - immutable borrow later used here
+
+error: aborting due to 10 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0596.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/async-await/pin-ergonomics/borrow.rs b/tests/ui/async-await/pin-ergonomics/borrow.rs
new file mode 100644
index 00000000000..e33f3c1fa26
--- /dev/null
+++ b/tests/ui/async-await/pin-ergonomics/borrow.rs
@@ -0,0 +1,31 @@
+//@ check-pass
+
+#![feature(pin_ergonomics)]
+#![allow(dead_code, incomplete_features)]
+
+// Makes sure we can handle `&pin mut place` and `&pin const place` as sugar for
+// `unsafe { Pin::new_unchecked(&mut place) }` and `Pin::new(&place)`.
+
+use std::pin::Pin;
+
+struct Foo;
+
+fn foo_pin_mut(_: Pin<&mut Foo>) {
+}
+
+fn foo_pin_ref(_: Pin<&Foo>) {
+}
+
+fn bar() {
+    let mut x: Pin<&mut _> = &pin mut Foo;
+    foo_pin_mut(x.as_mut());
+    foo_pin_mut(x.as_mut());
+    foo_pin_ref(x);
+
+    let x: Pin<&_> = &pin const Foo;
+
+    foo_pin_ref(x);
+    foo_pin_ref(x);
+}
+
+fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
index 663a83a665c..7746654555d 100644
--- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
+++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
@@ -17,6 +17,10 @@ fn foo(mut x: Pin<&mut Foo>) {
     let _y: &pin mut Foo = x; //~ ERROR pinned reference syntax is experimental
 }
 
+fn foo_const(x: Pin<&Foo>) {
+    let _y: &pin const Foo = x; //~ ERROR pinned reference syntax is experimental
+}
+
 fn foo_sugar(_: &pin mut Foo) {} //~ ERROR pinned reference syntax is experimental
 
 fn bar(x: Pin<&mut Foo>) {
@@ -31,6 +35,18 @@ fn baz(mut x: Pin<&mut Foo>) {
 
 fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental
 
+fn borrows() {
+    let mut x: Pin<&mut _> = &pin mut Foo; //~ ERROR pinned reference syntax is experimental
+    foo(x.as_mut());
+    foo(x.as_mut());
+    foo_const(x.as_ref());
+
+    let x: Pin<&_> = &pin const Foo; //~ ERROR pinned reference syntax is experimental
+
+    foo_const(x);
+    foo_const(x);
+}
+
 #[cfg(any())]
 mod not_compiled {
     use std::pin::Pin;
@@ -63,6 +79,18 @@ mod not_compiled {
     }
 
     fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental
+
+    fn borrows() {
+        let mut x: Pin<&mut _> = &pin mut Foo; //~ ERROR pinned reference syntax is experimental
+        foo(x.as_mut());
+        foo(x.as_mut());
+        foo_const(x.as_ref());
+
+        let x: Pin<&_> = &pin const Foo; //~ ERROR pinned reference syntax is experimental
+
+        foo_const(x);
+        foo_const(x);
+    }
 }
 
 fn main() {}
diff --git a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
index 8ed7543d86e..a8890254fac 100644
--- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
+++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
@@ -29,7 +29,17 @@ LL |     let _y: &pin mut Foo = x;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:20:18
+  --> $DIR/feature-gate-pin_ergonomics.rs:21:14
+   |
+LL |     let _y: &pin const Foo = x;
+   |              ^^^
+   |
+   = note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
+   = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: pinned reference syntax is experimental
+  --> $DIR/feature-gate-pin_ergonomics.rs:24:18
    |
 LL | fn foo_sugar(_: &pin mut Foo) {}
    |                  ^^^
@@ -39,7 +49,7 @@ LL | fn foo_sugar(_: &pin mut Foo) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:32:18
+  --> $DIR/feature-gate-pin_ergonomics.rs:36:18
    |
 LL | fn baz_sugar(_: &pin const Foo) {}
    |                  ^^^
@@ -49,7 +59,27 @@ LL | fn baz_sugar(_: &pin const Foo) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:43:23
+  --> $DIR/feature-gate-pin_ergonomics.rs:39:31
+   |
+LL |     let mut x: Pin<&mut _> = &pin mut Foo;
+   |                               ^^^
+   |
+   = note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
+   = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: pinned reference syntax is experimental
+  --> $DIR/feature-gate-pin_ergonomics.rs:44:23
+   |
+LL |     let x: Pin<&_> = &pin const Foo;
+   |                       ^^^
+   |
+   = note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
+   = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: pinned reference syntax is experimental
+  --> $DIR/feature-gate-pin_ergonomics.rs:59:23
    |
 LL |         fn foo_sugar(&pin mut self) {}
    |                       ^^^
@@ -59,7 +89,7 @@ LL |         fn foo_sugar(&pin mut self) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:44:29
+  --> $DIR/feature-gate-pin_ergonomics.rs:60:29
    |
 LL |         fn foo_sugar_const(&pin const self) {}
    |                             ^^^
@@ -69,7 +99,7 @@ LL |         fn foo_sugar_const(&pin const self) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:50:18
+  --> $DIR/feature-gate-pin_ergonomics.rs:66:18
    |
 LL |         let _y: &pin mut Foo = x;
    |                  ^^^
@@ -79,7 +109,7 @@ LL |         let _y: &pin mut Foo = x;
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:53:22
+  --> $DIR/feature-gate-pin_ergonomics.rs:69:22
    |
 LL |     fn foo_sugar(_: &pin mut Foo) {}
    |                      ^^^
@@ -89,7 +119,7 @@ LL |     fn foo_sugar(_: &pin mut Foo) {}
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:65:22
+  --> $DIR/feature-gate-pin_ergonomics.rs:81:22
    |
 LL |     fn baz_sugar(_: &pin const Foo) {}
    |                      ^^^
@@ -98,8 +128,28 @@ LL |     fn baz_sugar(_: &pin const Foo) {}
    = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
    = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
 
+error[E0658]: pinned reference syntax is experimental
+  --> $DIR/feature-gate-pin_ergonomics.rs:84:35
+   |
+LL |         let mut x: Pin<&mut _> = &pin mut Foo;
+   |                                   ^^^
+   |
+   = note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
+   = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
+error[E0658]: pinned reference syntax is experimental
+  --> $DIR/feature-gate-pin_ergonomics.rs:89:27
+   |
+LL |         let x: Pin<&_> = &pin const Foo;
+   |                           ^^^
+   |
+   = note: see issue #130494 <https://github.com/rust-lang/rust/issues/130494> for more information
+   = help: add `#![feature(pin_ergonomics)]` to the crate attributes to enable
+   = note: this compiler was built on YYYY-MM-DD; consider upgrading it if it is out of date
+
 error[E0382]: use of moved value: `x`
-  --> $DIR/feature-gate-pin_ergonomics.rs:24:9
+  --> $DIR/feature-gate-pin_ergonomics.rs:28:9
    |
 LL | fn bar(x: Pin<&mut Foo>) {
    |        - move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
@@ -117,7 +167,7 @@ LL | fn foo(mut x: Pin<&mut Foo>) {
    |    in this function
 
 error[E0382]: use of moved value: `x`
-  --> $DIR/feature-gate-pin_ergonomics.rs:29:5
+  --> $DIR/feature-gate-pin_ergonomics.rs:33:5
    |
 LL | fn baz(mut x: Pin<&mut Foo>) {
    |        ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
@@ -136,7 +186,7 @@ help: consider reborrowing the `Pin` instead of moving it
 LL |     x.as_mut().foo();
    |      +++++++++
 
-error: aborting due to 12 previous errors
+error: aborting due to 17 previous errors
 
 Some errors have detailed explanations: E0382, E0658.
 For more information about an error, try `rustc --explain E0382`.