about summary refs log tree commit diff
diff options
context:
space:
mode:
authorMichael Goulet <michael@errs.io>2025-03-06 12:22:08 -0500
committerGitHub <noreply@github.com>2025-03-06 12:22:08 -0500
commit91826b687cb29549df33c7e4029563e3a3861fa0 (patch)
tree691dd2cb4ee55d0011e477048b472214242e2738
parent30f168ef811aec63124eac677e14699baa9395bd (diff)
parent50d0f992acf3e7b4f0801a6a749e379a616a71d8 (diff)
downloadrust-91826b687cb29549df33c7e4029563e3a3861fa0.tar.gz
rust-91826b687cb29549df33c7e4029563e3a3861fa0.zip
Rollup merge of #135733 - frank-king:feature/pin-self-receiver, r=oli-obk,traviscross
Implement `&pin const self` and `&pin mut self` sugars

This PR implements part of #130494.

It introduces the sugars `&pin const self` and `&pin mut self` for `self: Pin<&Self>` and `self: Pin<&mut Self>`.
-rw-r--r--compiler/rustc_ast/src/ast.rs21
-rw-r--r--compiler/rustc_ast_pretty/src/pprust/state.rs7
-rw-r--r--compiler/rustc_parse/src/parser/item.rs62
-rw-r--r--src/tools/rustfmt/src/items.rs77
-rw-r--r--src/tools/rustfmt/tests/source/pin_sugar.rs10
-rw-r--r--src/tools/rustfmt/tests/target/pin_sugar.rs9
-rw-r--r--tests/pretty/pin-ergonomics.rs24
-rw-r--r--tests/ui/async-await/pin-ergonomics/sugar-self.rs46
-rw-r--r--tests/ui/feature-gates/feature-gate-pin_ergonomics.rs40
-rw-r--r--tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr88
10 files changed, 308 insertions, 76 deletions
diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs
index fb6b36e1a09..11fc409cf43 100644
--- a/compiler/rustc_ast/src/ast.rs
+++ b/compiler/rustc_ast/src/ast.rs
@@ -2641,6 +2641,8 @@ pub enum SelfKind {
     Value(Mutability),
     /// `&'lt self`, `&'lt mut self`
     Region(Option<Lifetime>, Mutability),
+    /// `&'lt pin const self`, `&'lt pin mut self`
+    Pinned(Option<Lifetime>, Mutability),
     /// `self: TYPE`, `mut self: TYPE`
     Explicit(P<Ty>, Mutability),
 }
@@ -2650,6 +2652,8 @@ impl SelfKind {
         match self {
             SelfKind::Region(None, mutbl) => mutbl.ref_prefix_str().to_string(),
             SelfKind::Region(Some(lt), mutbl) => format!("&{lt} {}", mutbl.prefix_str()),
+            SelfKind::Pinned(None, mutbl) => format!("&pin {}", mutbl.ptr_str()),
+            SelfKind::Pinned(Some(lt), mutbl) => format!("&{lt} pin {}", mutbl.ptr_str()),
             SelfKind::Value(_) | SelfKind::Explicit(_, _) => {
                 unreachable!("if we had an explicit self, we wouldn't be here")
             }
@@ -2666,11 +2670,13 @@ impl Param {
             if ident.name == kw::SelfLower {
                 return match self.ty.kind {
                     TyKind::ImplicitSelf => Some(respan(self.pat.span, SelfKind::Value(mutbl))),
-                    TyKind::Ref(lt, MutTy { ref ty, mutbl })
-                    | TyKind::PinnedRef(lt, MutTy { ref ty, mutbl })
+                    TyKind::Ref(lt, MutTy { ref ty, mutbl }) if ty.kind.is_implicit_self() => {
+                        Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
+                    }
+                    TyKind::PinnedRef(lt, MutTy { ref ty, mutbl })
                         if ty.kind.is_implicit_self() =>
                     {
-                        Some(respan(self.pat.span, SelfKind::Region(lt, mutbl)))
+                        Some(respan(self.pat.span, SelfKind::Pinned(lt, mutbl)))
                     }
                     _ => Some(respan(
                         self.pat.span.to(self.ty.span),
@@ -2712,6 +2718,15 @@ impl Param {
                     tokens: None,
                 }),
             ),
+            SelfKind::Pinned(lt, mutbl) => (
+                mutbl,
+                P(Ty {
+                    id: DUMMY_NODE_ID,
+                    kind: TyKind::PinnedRef(lt, MutTy { ty: infer_ty, mutbl }),
+                    span,
+                    tokens: None,
+                }),
+            ),
         };
         Param {
             attrs,
diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs
index d747237f76d..01fc272a458 100644
--- a/compiler/rustc_ast_pretty/src/pprust/state.rs
+++ b/compiler/rustc_ast_pretty/src/pprust/state.rs
@@ -1783,6 +1783,13 @@ impl<'a> State<'a> {
                 self.print_mutability(*m, false);
                 self.word("self")
             }
+            SelfKind::Pinned(lt, m) => {
+                self.word("&");
+                self.print_opt_lifetime(lt);
+                self.word("pin ");
+                self.print_mutability(*m, true);
+                self.word("self")
+            }
             SelfKind::Explicit(typ, m) => {
                 self.print_mutability(*m, false);
                 self.word("self");
diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs
index 3f642a7ac1f..c3b1956ad2e 100644
--- a/compiler/rustc_parse/src/parser/item.rs
+++ b/compiler/rustc_parse/src/parser/item.rs
@@ -2954,14 +2954,27 @@ impl<'a> Parser<'a> {
             }
             _ => unreachable!(),
         };
+        // is lifetime `n` tokens ahead?
+        let is_lifetime = |this: &Self, n| this.look_ahead(n, |t| t.is_lifetime());
         // Is `self` `n` tokens ahead?
         let is_isolated_self = |this: &Self, n| {
             this.is_keyword_ahead(n, &[kw::SelfLower])
                 && this.look_ahead(n + 1, |t| t != &token::PathSep)
         };
+        // Is `pin const self` `n` tokens ahead?
+        let is_isolated_pin_const_self = |this: &Self, n| {
+            this.look_ahead(n, |token| token.is_ident_named(sym::pin))
+                && this.is_keyword_ahead(n + 1, &[kw::Const])
+                && is_isolated_self(this, n + 2)
+        };
         // Is `mut self` `n` tokens ahead?
         let is_isolated_mut_self =
             |this: &Self, n| this.is_keyword_ahead(n, &[kw::Mut]) && is_isolated_self(this, n + 1);
+        // Is `pin mut self` `n` tokens ahead?
+        let is_isolated_pin_mut_self = |this: &Self, n| {
+            this.look_ahead(n, |token| token.is_ident_named(sym::pin))
+                && is_isolated_mut_self(this, n + 1)
+        };
         // Parse `self` or `self: TYPE`. We already know the current token is `self`.
         let parse_self_possibly_typed = |this: &mut Self, m| {
             let eself_ident = expect_self_ident(this);
@@ -3012,26 +3025,35 @@ impl<'a> Parser<'a> {
         let eself_lo = self.token.span;
         let (eself, eself_ident, eself_hi) = match self.token.uninterpolate().kind {
             token::And => {
-                let eself = if is_isolated_self(self, 1) {
-                    // `&self`
-                    self.bump();
-                    SelfKind::Region(None, Mutability::Not)
-                } else if is_isolated_mut_self(self, 1) {
-                    // `&mut self`
-                    self.bump();
-                    self.bump();
-                    SelfKind::Region(None, Mutability::Mut)
-                } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_self(self, 2) {
-                    // `&'lt self`
-                    self.bump();
-                    let lt = self.expect_lifetime();
-                    SelfKind::Region(Some(lt), Mutability::Not)
-                } else if self.look_ahead(1, |t| t.is_lifetime()) && is_isolated_mut_self(self, 2) {
-                    // `&'lt mut self`
-                    self.bump();
-                    let lt = self.expect_lifetime();
-                    self.bump();
-                    SelfKind::Region(Some(lt), Mutability::Mut)
+                let has_lifetime = is_lifetime(self, 1);
+                let skip_lifetime_count = has_lifetime as usize;
+                let eself = if is_isolated_self(self, skip_lifetime_count + 1) {
+                    // `&{'lt} self`
+                    self.bump(); // &
+                    let lifetime = has_lifetime.then(|| self.expect_lifetime());
+                    SelfKind::Region(lifetime, Mutability::Not)
+                } else if is_isolated_mut_self(self, skip_lifetime_count + 1) {
+                    // `&{'lt} mut self`
+                    self.bump(); // &
+                    let lifetime = has_lifetime.then(|| self.expect_lifetime());
+                    self.bump(); // mut
+                    SelfKind::Region(lifetime, Mutability::Mut)
+                } else if is_isolated_pin_const_self(self, skip_lifetime_count + 1) {
+                    // `&{'lt} pin const self`
+                    self.bump(); // &
+                    let lifetime = has_lifetime.then(|| self.expect_lifetime());
+                    self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
+                    self.bump(); // pin
+                    self.bump(); // const
+                    SelfKind::Pinned(lifetime, Mutability::Not)
+                } else if is_isolated_pin_mut_self(self, skip_lifetime_count + 1) {
+                    // `&{'lt} pin mut self`
+                    self.bump(); // &
+                    let lifetime = has_lifetime.then(|| self.expect_lifetime());
+                    self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span);
+                    self.bump(); // pin
+                    self.bump(); // mut
+                    SelfKind::Pinned(lifetime, Mutability::Mut)
                 } else {
                     // `&not_self`
                     return Ok(None);
diff --git a/src/tools/rustfmt/src/items.rs b/src/tools/rustfmt/src/items.rs
index 457d0afe3b5..3fb3284e3d7 100644
--- a/src/tools/rustfmt/src/items.rs
+++ b/src/tools/rustfmt/src/items.rs
@@ -2359,6 +2359,21 @@ impl Rewrite for ast::Param {
     }
 }
 
+fn rewrite_opt_lifetime(
+    context: &RewriteContext<'_>,
+    lifetime: Option<ast::Lifetime>,
+) -> RewriteResult {
+    let Some(l) = lifetime else {
+        return Ok(String::new());
+    };
+    let mut result = l.rewrite_result(
+        context,
+        Shape::legacy(context.config.max_width(), Indent::empty()),
+    )?;
+    result.push(' ');
+    Ok(result)
+}
+
 fn rewrite_explicit_self(
     context: &RewriteContext<'_>,
     explicit_self: &ast::ExplicitSelf,
@@ -2367,58 +2382,34 @@ fn rewrite_explicit_self(
     shape: Shape,
     has_multiple_attr_lines: bool,
 ) -> RewriteResult {
-    match explicit_self.node {
+    let self_str = match explicit_self.node {
         ast::SelfKind::Region(lt, m) => {
             let mut_str = format_mutability(m);
-            match lt {
-                Some(ref l) => {
-                    let lifetime_str = l.rewrite_result(
-                        context,
-                        Shape::legacy(context.config.max_width(), Indent::empty()),
-                    )?;
-                    Ok(combine_strs_with_missing_comments(
-                        context,
-                        param_attrs,
-                        &format!("&{lifetime_str} {mut_str}self"),
-                        span,
-                        shape,
-                        !has_multiple_attr_lines,
-                    )?)
-                }
-                None => Ok(combine_strs_with_missing_comments(
-                    context,
-                    param_attrs,
-                    &format!("&{mut_str}self"),
-                    span,
-                    shape,
-                    !has_multiple_attr_lines,
-                )?),
-            }
+            let lifetime_str = rewrite_opt_lifetime(context, lt)?;
+            format!("&{lifetime_str}{mut_str}self")
+        }
+        ast::SelfKind::Pinned(lt, m) => {
+            let mut_str = m.ptr_str();
+            let lifetime_str = rewrite_opt_lifetime(context, lt)?;
+            format!("&{lifetime_str}pin {mut_str} self")
         }
         ast::SelfKind::Explicit(ref ty, mutability) => {
             let type_str = ty.rewrite_result(
                 context,
                 Shape::legacy(context.config.max_width(), Indent::empty()),
             )?;
-
-            Ok(combine_strs_with_missing_comments(
-                context,
-                param_attrs,
-                &format!("{}self: {}", format_mutability(mutability), type_str),
-                span,
-                shape,
-                !has_multiple_attr_lines,
-            )?)
+            format!("{}self: {}", format_mutability(mutability), type_str)
         }
-        ast::SelfKind::Value(mutability) => Ok(combine_strs_with_missing_comments(
-            context,
-            param_attrs,
-            &format!("{}self", format_mutability(mutability)),
-            span,
-            shape,
-            !has_multiple_attr_lines,
-        )?),
-    }
+        ast::SelfKind::Value(mutability) => format!("{}self", format_mutability(mutability)),
+    };
+    Ok(combine_strs_with_missing_comments(
+        context,
+        param_attrs,
+        &self_str,
+        span,
+        shape,
+        !has_multiple_attr_lines,
+    )?)
 }
 
 pub(crate) fn span_lo_for_param(param: &ast::Param) -> BytePos {
diff --git a/src/tools/rustfmt/tests/source/pin_sugar.rs b/src/tools/rustfmt/tests/source/pin_sugar.rs
index 0eb3c0770c4..370dfbc196a 100644
--- a/src/tools/rustfmt/tests/source/pin_sugar.rs
+++ b/src/tools/rustfmt/tests/source/pin_sugar.rs
@@ -8,3 +8,13 @@ fn g<'a>(x: &  'a pin const  i32) {}
 fn h<'a>(x: &  'a pin  
 mut i32) {}
 fn i(x: &pin      mut  i32) {}
+
+struct Foo;
+
+impl Foo {
+    fn f(&pin   const self) {}
+    fn g<'a>(&   'a pin const    self) {}
+    fn h<'a>(&    'a pin
+mut self) {}
+    fn i(&pin      mut   self) {}
+}
diff --git a/src/tools/rustfmt/tests/target/pin_sugar.rs b/src/tools/rustfmt/tests/target/pin_sugar.rs
index c9fa883e238..7d04efb1b32 100644
--- a/src/tools/rustfmt/tests/target/pin_sugar.rs
+++ b/src/tools/rustfmt/tests/target/pin_sugar.rs
@@ -7,3 +7,12 @@ fn f(x: &pin const i32) {}
 fn g<'a>(x: &'a pin const i32) {}
 fn h<'a>(x: &'a pin mut i32) {}
 fn i(x: &pin mut i32) {}
+
+struct Foo;
+
+impl Foo {
+    fn f(&pin const self) {}
+    fn g<'a>(&'a pin const self) {}
+    fn h<'a>(&'a pin mut self) {}
+    fn i(&pin mut self) {}
+}
diff --git a/tests/pretty/pin-ergonomics.rs b/tests/pretty/pin-ergonomics.rs
new file mode 100644
index 00000000000..47ffc97b118
--- /dev/null
+++ b/tests/pretty/pin-ergonomics.rs
@@ -0,0 +1,24 @@
+//@ pp-exact
+
+#![feature(pin_ergonomics)]
+#![allow(dead_code, incomplete_features)]
+
+struct Foo;
+
+impl Foo {
+    fn baz(&pin mut self) {}
+
+    fn baz_const(&pin const self) {}
+
+    fn baz_lt<'a>(&'a pin mut self) {}
+
+    fn baz_const_lt(&'_ pin const self) {}
+}
+
+fn foo(_: &pin mut Foo) {}
+fn foo_lt<'a>(_: &'a pin mut Foo) {}
+
+fn foo_const(_: &pin const Foo) {}
+fn foo_const_lt(_: &'_ pin const Foo) {}
+
+fn main() {}
diff --git a/tests/ui/async-await/pin-ergonomics/sugar-self.rs b/tests/ui/async-await/pin-ergonomics/sugar-self.rs
new file mode 100644
index 00000000000..3d71b54b1ae
--- /dev/null
+++ b/tests/ui/async-await/pin-ergonomics/sugar-self.rs
@@ -0,0 +1,46 @@
+//@ check-pass
+
+#![feature(pin_ergonomics)]
+#![allow(dead_code, incomplete_features)]
+
+// Makes sure we can handle `&pin mut self` and `&pin const self` as sugar for
+// `self: Pin<&mut Self>` and `self: Pin<&Self>`.
+
+use std::pin::Pin;
+
+struct Foo;
+
+impl Foo {
+    fn baz(&pin mut self) {}
+
+    fn baz_const(&pin const self) {}
+
+    fn baz_lt<'a>(&'a pin mut self) {}
+
+    fn baz_const_lt(&'_ pin const self) {}
+}
+
+fn foo(_: &pin mut Foo) {}
+
+fn foo_const(_: &pin const Foo) {}
+
+fn bar(x: &pin mut Foo) {
+    // For the calls below to work we need to automatically reborrow,
+    // as if the user had written `foo(x.as_mut())`.
+    foo(x);
+    foo(x);
+
+    Foo::baz(x);
+    Foo::baz(x);
+
+    // make sure we can reborrow &mut as &.
+    foo_const(x);
+    Foo::baz_const(x);
+
+    let x: &pin const _ = Pin::new(&Foo);
+
+    foo_const(x); // make sure reborrowing from & to & works.
+    foo_const(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 4624faf1e53..663a83a665c 100644
--- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
+++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
@@ -7,9 +7,13 @@ struct Foo;
 impl Foo {
     fn foo(self: Pin<&mut Self>) {
     }
+    fn foo_sugar(&pin mut self) {} //~ ERROR pinned reference syntax is experimental
+    fn foo_sugar_const(&pin const self) {} //~ ERROR pinned reference syntax is experimental
 }
 
-fn foo(x: Pin<&mut Foo>) {
+fn foo(mut x: Pin<&mut Foo>) {
+    Foo::foo_sugar(x.as_mut());
+    Foo::foo_sugar_const(x.as_ref());
     let _y: &pin mut Foo = x; //~ ERROR pinned reference syntax is experimental
 }
 
@@ -27,4 +31,38 @@ fn baz(mut x: Pin<&mut Foo>) {
 
 fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental
 
+#[cfg(any())]
+mod not_compiled {
+    use std::pin::Pin;
+
+    struct Foo;
+
+    impl Foo {
+        fn foo(self: Pin<&mut Self>) {
+        }
+        fn foo_sugar(&pin mut self) {} //~ ERROR pinned reference syntax is experimental
+        fn foo_sugar_const(&pin const self) {} //~ ERROR pinned reference syntax is experimental
+    }
+
+    fn foo(mut x: Pin<&mut Foo>) {
+        Foo::foo_sugar(x.as_mut());
+        Foo::foo_sugar_const(x.as_ref());
+        let _y: &pin mut 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>) {
+        foo(x);
+        foo(x);
+    }
+
+    fn baz(mut x: Pin<&mut Foo>) {
+        x.foo();
+        x.foo();
+    }
+
+    fn baz_sugar(_: &pin const Foo) {} //~ ERROR pinned reference syntax is experimental
+}
+
 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 dd93a7be1ad..8ed7543d86e 100644
--- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
+++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
@@ -1,5 +1,25 @@
 error[E0658]: pinned reference syntax is experimental
-  --> $DIR/feature-gate-pin_ergonomics.rs:13:14
+  --> $DIR/feature-gate-pin_ergonomics.rs:10:19
+   |
+LL |     fn foo_sugar(&pin mut self) {}
+   |                   ^^^
+   |
+   = 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:11:25
+   |
+LL |     fn foo_sugar_const(&pin const self) {}
+   |                         ^^^
+   |
+   = 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:17:14
    |
 LL |     let _y: &pin mut Foo = x;
    |              ^^^
@@ -9,7 +29,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:16:18
+  --> $DIR/feature-gate-pin_ergonomics.rs:20:18
    |
 LL | fn foo_sugar(_: &pin mut Foo) {}
    |                  ^^^
@@ -19,7 +39,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:28:18
+  --> $DIR/feature-gate-pin_ergonomics.rs:32:18
    |
 LL | fn baz_sugar(_: &pin const Foo) {}
    |                  ^^^
@@ -28,8 +48,58 @@ 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:43:23
+   |
+LL |         fn foo_sugar(&pin mut self) {}
+   |                       ^^^
+   |
+   = 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:29
+   |
+LL |         fn foo_sugar_const(&pin const self) {}
+   |                             ^^^
+   |
+   = 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:50:18
+   |
+LL |         let _y: &pin mut 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:53:22
+   |
+LL |     fn foo_sugar(_: &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:65:22
+   |
+LL |     fn baz_sugar(_: &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:20:9
+  --> $DIR/feature-gate-pin_ergonomics.rs:24:9
    |
 LL | fn bar(x: Pin<&mut Foo>) {
    |        - move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait
@@ -39,15 +109,15 @@ LL |     foo(x);
    |         ^ value used here after move
    |
 note: consider changing this parameter type in function `foo` to borrow instead if owning the value isn't necessary
-  --> $DIR/feature-gate-pin_ergonomics.rs:12:11
+  --> $DIR/feature-gate-pin_ergonomics.rs:14:15
    |
-LL | fn foo(x: Pin<&mut Foo>) {
-   |    ---    ^^^^^^^^^^^^^ this parameter takes ownership of the value
+LL | fn foo(mut x: Pin<&mut Foo>) {
+   |    ---        ^^^^^^^^^^^^^ this parameter takes ownership of the value
    |    |
    |    in this function
 
 error[E0382]: use of moved value: `x`
-  --> $DIR/feature-gate-pin_ergonomics.rs:25:5
+  --> $DIR/feature-gate-pin_ergonomics.rs:29: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
@@ -66,7 +136,7 @@ help: consider reborrowing the `Pin` instead of moving it
 LL |     x.as_mut().foo();
    |      +++++++++
 
-error: aborting due to 5 previous errors
+error: aborting due to 12 previous errors
 
 Some errors have detailed explanations: E0382, E0658.
 For more information about an error, try `rustc --explain E0382`.