diff --git a/compiler/rustc_ast/src/ast.rs b/compiler/rustc_ast/src/ast.rs index f433f2eca1a80..5ee8e8a4178e1 100644 --- a/compiler/rustc_ast/src/ast.rs +++ b/compiler/rustc_ast/src/ast.rs @@ -21,7 +21,7 @@ use std::borrow::Cow; use std::{cmp, fmt, mem}; -pub use rustc_ast_ir::{Movability, Mutability}; +pub use rustc_ast_ir::{Movability, Mutability, Pinnedness}; use rustc_data_structures::packed::Pu128; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::stack::ensure_sufficient_stack; @@ -2159,6 +2159,8 @@ pub enum TyKind { Ptr(MutTy), /// A reference (`&'a T` or `&'a mut T`). Ref(Option, MutTy), + /// A pinned reference (`&'a pin const T` or `&'a pin mut T`). + PinnedRef(Option, MutTy), /// A bare function (e.g., `fn(usize) -> bool`). BareFn(P), /// The never type (`!`). @@ -2481,7 +2483,10 @@ 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 }) if ty.kind.is_implicit_self() => { + TyKind::Ref(lt, MutTy { ref ty, 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( diff --git a/compiler/rustc_ast/src/mut_visit.rs b/compiler/rustc_ast/src/mut_visit.rs index 1bef51aa73f7b..e459895ccfd57 100644 --- a/compiler/rustc_ast/src/mut_visit.rs +++ b/compiler/rustc_ast/src/mut_visit.rs @@ -485,7 +485,7 @@ pub fn walk_ty(vis: &mut T, ty: &mut P) { } TyKind::Slice(ty) => vis.visit_ty(ty), TyKind::Ptr(mt) => vis.visit_mt(mt), - TyKind::Ref(lt, mt) => { + TyKind::Ref(lt, mt) | TyKind::PinnedRef(lt, mt) => { visit_opt(lt, |lt| vis.visit_lifetime(lt)); vis.visit_mt(mt); } diff --git a/compiler/rustc_ast/src/util/classify.rs b/compiler/rustc_ast/src/util/classify.rs index 1a80a9ccdbf54..8fdaf99585089 100644 --- a/compiler/rustc_ast/src/util/classify.rs +++ b/compiler/rustc_ast/src/util/classify.rs @@ -247,7 +247,9 @@ fn type_trailing_braced_mac_call(mut ty: &ast::Ty) -> Option<&ast::MacCall> { break (mac.args.delim == Delimiter::Brace).then_some(mac); } - ast::TyKind::Ptr(mut_ty) | ast::TyKind::Ref(_, mut_ty) => { + ast::TyKind::Ptr(mut_ty) + | ast::TyKind::Ref(_, mut_ty) + | ast::TyKind::PinnedRef(_, mut_ty) => { ty = &mut_ty.ty; } diff --git a/compiler/rustc_ast/src/visit.rs b/compiler/rustc_ast/src/visit.rs index bae7ad93f90fa..bcf222f0410d3 100644 --- a/compiler/rustc_ast/src/visit.rs +++ b/compiler/rustc_ast/src/visit.rs @@ -499,7 +499,8 @@ pub fn walk_ty<'a, V: Visitor<'a>>(visitor: &mut V, typ: &'a Ty) -> V::Result { match kind { TyKind::Slice(ty) | TyKind::Paren(ty) => try_visit!(visitor.visit_ty(ty)), TyKind::Ptr(MutTy { ty, mutbl: _ }) => try_visit!(visitor.visit_ty(ty)), - TyKind::Ref(opt_lifetime, MutTy { ty, mutbl: _ }) => { + TyKind::Ref(opt_lifetime, MutTy { ty, mutbl: _ }) + | TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl: _ }) => { visit_opt!(visitor, visit_lifetime, opt_lifetime, LifetimeCtxt::Ref); try_visit!(visitor.visit_ty(ty)); } diff --git a/compiler/rustc_ast_ir/src/lib.rs b/compiler/rustc_ast_ir/src/lib.rs index eeed5d3615139..ff9d940ce9f28 100644 --- a/compiler/rustc_ast_ir/src/lib.rs +++ b/compiler/rustc_ast_ir/src/lib.rs @@ -79,3 +79,10 @@ impl Mutability { matches!(self, Self::Not) } } + +#[derive(Clone, PartialEq, Eq, PartialOrd, Ord, Hash, Debug, Copy)] +#[cfg_attr(feature = "nightly", derive(Encodable, Decodable, HashStable_NoContext))] +pub enum Pinnedness { + Not, + Pinned, +} diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index e105026ebd19d..e7b03e1174895 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -638,7 +638,8 @@ impl<'hir> LoweringContext<'_, 'hir> { self.lower_span(span), Some(self.allow_gen_future.clone()), ); - let resume_ty = self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span); + let resume_ty = + self.make_lang_item_qpath(hir::LangItem::ResumeTy, unstable_span, None); let input_ty = hir::Ty { hir_id: self.next_id(), kind: hir::TyKind::Path(resume_ty), @@ -2063,7 +2064,7 @@ impl<'hir> LoweringContext<'_, 'hir> { lang_item: hir::LangItem, name: Symbol, ) -> hir::Expr<'hir> { - let qpath = self.make_lang_item_qpath(lang_item, self.lower_span(span)); + let qpath = self.make_lang_item_qpath(lang_item, self.lower_span(span), None); let path = hir::ExprKind::Path(hir::QPath::TypeRelative( self.arena.alloc(self.ty(span, hir::TyKind::Path(qpath))), self.arena.alloc(hir::PathSegment::new( diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index efd3ae336afb8..903bba9c07a7d 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -55,8 +55,8 @@ use rustc_errors::{DiagArgFromDisplay, DiagCtxtHandle, StashKey}; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, LocalDefIdMap, CRATE_DEF_ID, LOCAL_CRATE}; use rustc_hir::{ - self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, MissingLifetimeKind, ParamName, - TraitCandidate, + self as hir, ConstArg, GenericArg, HirId, ItemLocalMap, LangItem, MissingLifetimeKind, + ParamName, TraitCandidate, }; use rustc_index::{Idx, IndexSlice, IndexVec}; use rustc_macros::extension; @@ -756,8 +756,13 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { res } - fn make_lang_item_qpath(&mut self, lang_item: hir::LangItem, span: Span) -> hir::QPath<'hir> { - hir::QPath::Resolved(None, self.make_lang_item_path(lang_item, span, None)) + fn make_lang_item_qpath( + &mut self, + lang_item: hir::LangItem, + span: Span, + args: Option<&'hir hir::GenericArgs<'hir>>, + ) -> hir::QPath<'hir> { + hir::QPath::Resolved(None, self.make_lang_item_path(lang_item, span, args)) } fn make_lang_item_path( @@ -1300,6 +1305,32 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { let lifetime = self.lower_lifetime(®ion); hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx)) } + TyKind::PinnedRef(region, mt) => { + let region = region.unwrap_or_else(|| { + let id = if let Some(LifetimeRes::ElidedAnchor { start, end }) = + self.resolver.get_lifetime_res(t.id) + { + debug_assert_eq!(start.plus(1), end); + start + } else { + self.next_node_id() + }; + let span = self.tcx.sess.source_map().start_point(t.span).shrink_to_hi(); + Lifetime { ident: Ident::new(kw::UnderscoreLifetime, span), id } + }); + let lifetime = self.lower_lifetime(®ion); + let kind = hir::TyKind::Ref(lifetime, self.lower_mt(mt, itctx)); + let span = self.lower_span(t.span); + let arg = hir::Ty { kind, span, hir_id: self.next_id() }; + let args = self.arena.alloc(hir::GenericArgs { + args: self.arena.alloc([hir::GenericArg::Type(self.arena.alloc(arg))]), + constraints: &[], + parenthesized: hir::GenericArgsParentheses::No, + span_ext: span, + }); + let path = self.make_lang_item_qpath(LangItem::Pin, span, Some(args)); + hir::TyKind::Path(path) + } TyKind::BareFn(f) => { let generic_params = self.lower_lifetime_binder(t.id, &f.generic_params); hir::TyKind::BareFn(self.arena.alloc(hir::BareFnTy { @@ -1882,10 +1913,14 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { // Given we are only considering `ImplicitSelf` types, we needn't consider // the case where we have a mutable pattern to a reference as that would // no longer be an `ImplicitSelf`. - TyKind::Ref(_, mt) if mt.ty.kind.is_implicit_self() => match mt.mutbl { - hir::Mutability::Not => hir::ImplicitSelfKind::RefImm, - hir::Mutability::Mut => hir::ImplicitSelfKind::RefMut, - }, + TyKind::Ref(_, mt) | TyKind::PinnedRef(_, mt) + if mt.ty.kind.is_implicit_self() => + { + match mt.mutbl { + hir::Mutability::Not => hir::ImplicitSelfKind::RefImm, + hir::Mutability::Mut => hir::ImplicitSelfKind::RefMut, + } + } _ => hir::ImplicitSelfKind::None, } }), diff --git a/compiler/rustc_ast_lowering/src/lifetime_collector.rs b/compiler/rustc_ast_lowering/src/lifetime_collector.rs index 76c957afa5461..42b8a6eea7601 100644 --- a/compiler/rustc_ast_lowering/src/lifetime_collector.rs +++ b/compiler/rustc_ast_lowering/src/lifetime_collector.rs @@ -95,7 +95,7 @@ impl<'ast> Visitor<'ast> for LifetimeCollectVisitor<'ast> { visit::walk_ty(self, t); self.current_binders.pop(); } - TyKind::Ref(None, _) => { + TyKind::Ref(None, _) | TyKind::PinnedRef(None, _) => { self.record_elided_anchor(t.id, t.span); visit::walk_ty(self, t); } diff --git a/compiler/rustc_ast_passes/src/feature_gate.rs b/compiler/rustc_ast_passes/src/feature_gate.rs index cfc534acd982e..3c7bdc50b023c 100644 --- a/compiler/rustc_ast_passes/src/feature_gate.rs +++ b/compiler/rustc_ast_passes/src/feature_gate.rs @@ -545,6 +545,7 @@ pub fn check_crate(krate: &ast::Crate, sess: &Session, features: &Features) { gate_all!(mut_ref, "mutable by-reference bindings are experimental"); gate_all!(global_registration, "global registration is experimental"); gate_all!(return_type_notation, "return type notation is experimental"); + gate_all!(pin_ergonomics, "pinned reference syntax is experimental"); if !visitor.features.never_patterns { if let Some(spans) = spans.get(&sym::never_patterns) { diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 3b1449d9a9113..156d7f421ad13 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -1163,6 +1163,12 @@ impl<'a> State<'a> { self.print_opt_lifetime(lifetime); self.print_mt(mt, false); } + ast::TyKind::PinnedRef(lifetime, mt) => { + self.word("&"); + self.print_opt_lifetime(lifetime); + self.word("pin "); + self.print_mt(mt, true); + } ast::TyKind::Never => { self.word("!"); } diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index ee03f780e16f5..886bbd33dbdcd 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -1,10 +1,9 @@ use std::fmt; -use rustc_ast as ast; use rustc_ast::util::parser::ExprPrecedence; use rustc_ast::{ - Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, LitKind, - TraitObjectSyntax, UintTy, + self as ast, Attribute, FloatTy, InlineAsmOptions, InlineAsmTemplatePiece, IntTy, Label, + LitKind, TraitObjectSyntax, UintTy, }; pub use rustc_ast::{ BinOp, BinOpKind, BindingMode, BorrowKind, ByRef, CaptureBy, ImplPolarity, IsAuto, Movability, diff --git a/compiler/rustc_parse/src/parser/ty.rs b/compiler/rustc_parse/src/parser/ty.rs index 66019ffbc0ab9..b4f8d63c163eb 100644 --- a/compiler/rustc_parse/src/parser/ty.rs +++ b/compiler/rustc_parse/src/parser/ty.rs @@ -3,8 +3,9 @@ use rustc_ast::token::{self, BinOpToken, Delimiter, IdentIsRaw, Token, TokenKind use rustc_ast::util::case::Case; use rustc_ast::{ self as ast, BareFnTy, BoundAsyncness, BoundConstness, BoundPolarity, FnRetTy, GenericBound, - GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, PolyTraitRef, - PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, DUMMY_NODE_ID, + GenericBounds, GenericParam, Generics, Lifetime, MacCall, MutTy, Mutability, Pinnedness, + PolyTraitRef, PreciseCapturingArg, TraitBoundModifiers, TraitObjectSyntax, Ty, TyKind, + DUMMY_NODE_ID, }; use rustc_errors::{Applicability, PResult}; use rustc_span::symbol::{kw, sym, Ident}; @@ -529,7 +530,10 @@ impl<'a> Parser<'a> { fn parse_borrowed_pointee(&mut self) -> PResult<'a, TyKind> { let and_span = self.prev_token.span; let mut opt_lifetime = self.check_lifetime().then(|| self.expect_lifetime()); - let mut mutbl = self.parse_mutability(); + let (pinned, mut mutbl) = match self.parse_pin_and_mut() { + Some(pin_mut) => pin_mut, + None => (Pinnedness::Not, self.parse_mutability()), + }; if self.token.is_lifetime() && mutbl == Mutability::Mut && opt_lifetime.is_none() { // A lifetime is invalid here: it would be part of a bare trait bound, which requires // it to be followed by a plus, but we disallow plus in the pointee type. @@ -565,7 +569,35 @@ impl<'a> Parser<'a> { self.bump_with((dyn_tok, dyn_tok_sp)); } let ty = self.parse_ty_no_plus()?; - Ok(TyKind::Ref(opt_lifetime, MutTy { ty, mutbl })) + Ok(match pinned { + Pinnedness::Not => TyKind::Ref(opt_lifetime, MutTy { ty, mutbl }), + Pinnedness::Pinned => TyKind::PinnedRef(opt_lifetime, MutTy { ty, mutbl }), + }) + } + + /// Parses `pin` and `mut` annotations on references. + /// + /// It must be either `pin const` or `pin mut`. + pub(crate) fn parse_pin_and_mut(&mut self) -> Option<(Pinnedness, Mutability)> { + if self.token.is_ident_named(sym::pin) { + let result = self.look_ahead(1, |token| { + if token.is_keyword(kw::Const) { + Some((Pinnedness::Pinned, Mutability::Not)) + } else if token.is_keyword(kw::Mut) { + Some((Pinnedness::Pinned, Mutability::Mut)) + } else { + None + } + }); + if result.is_some() { + self.psess.gated_spans.gate(sym::pin_ergonomics, self.token.span); + self.bump(); + self.bump(); + } + result + } else { + None + } } // Parses the `typeof(EXPR)`. diff --git a/compiler/rustc_passes/src/hir_stats.rs b/compiler/rustc_passes/src/hir_stats.rs index 38e8c3cd12de4..a455cd0a07f5e 100644 --- a/compiler/rustc_passes/src/hir_stats.rs +++ b/compiler/rustc_passes/src/hir_stats.rs @@ -605,6 +605,7 @@ impl<'v> ast_visit::Visitor<'v> for StatCollector<'v> { Array, Ptr, Ref, + PinnedRef, BareFn, Never, Tup, diff --git a/compiler/rustc_resolve/src/late.rs b/compiler/rustc_resolve/src/late.rs index 0aa351cad4043..d80bd6099f6ff 100644 --- a/compiler/rustc_resolve/src/late.rs +++ b/compiler/rustc_resolve/src/late.rs @@ -753,7 +753,7 @@ impl<'ra: 'ast, 'ast, 'tcx> Visitor<'ast> for LateResolutionVisitor<'_, 'ast, 'r let prev = self.diag_metadata.current_trait_object; let prev_ty = self.diag_metadata.current_type_path; match &ty.kind { - TyKind::Ref(None, _) => { + TyKind::Ref(None, _) | TyKind::PinnedRef(None, _) => { // Elided lifetime in reference: we resolve as if there was some lifetime `'_` with // NodeId `ty.id`. // This span will be used in case of elision failure. @@ -2275,7 +2275,7 @@ impl<'a, 'ast, 'ra: 'ast, 'tcx> LateResolutionVisitor<'a, 'ast, 'ra, 'tcx> { impl<'ra> Visitor<'ra> for FindReferenceVisitor<'_, '_, '_> { fn visit_ty(&mut self, ty: &'ra Ty) { trace!("FindReferenceVisitor considering ty={:?}", ty); - if let TyKind::Ref(lt, _) = ty.kind { + if let TyKind::Ref(lt, _) | TyKind::PinnedRef(lt, _) = ty.kind { // See if anything inside the &thing contains Self let mut visitor = SelfVisitor { r: self.r, impl_self: self.impl_self, self_found: false }; diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 1c584bf833862..7f8dc79d95d86 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -3467,7 +3467,7 @@ struct LifetimeFinder<'ast> { impl<'ast> Visitor<'ast> for LifetimeFinder<'ast> { fn visit_ty(&mut self, t: &'ast Ty) { - if let TyKind::Ref(_, mut_ty) = &t.kind { + if let TyKind::Ref(_, mut_ty) | TyKind::PinnedRef(_, mut_ty) = &t.kind { self.seen.push(t); if t.span.lo() == self.lifetime.lo() { self.found = Some(&mut_ty.ty); diff --git a/src/tools/clippy/clippy_utils/src/ast_utils.rs b/src/tools/clippy/clippy_utils/src/ast_utils.rs index de8bbb619f8e4..c4965b9841c15 100644 --- a/src/tools/clippy/clippy_utils/src/ast_utils.rs +++ b/src/tools/clippy/clippy_utils/src/ast_utils.rs @@ -722,8 +722,8 @@ pub fn eq_ty(l: &Ty, r: &Ty) -> bool { (Slice(l), Slice(r)) => eq_ty(l, r), (Array(le, ls), Array(re, rs)) => eq_ty(le, re) && eq_expr(&ls.value, &rs.value), (Ptr(l), Ptr(r)) => l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty), - (Ref(ll, l), Ref(rl, r)) => { - both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty) + (Ref(ll, lp, l), Ref(rl, rp, r)) => { + both(ll, rl, |l, r| eq_id(l.ident, r.ident)) && l.mutbl == r.mutbl && eq_ty(&l.ty, &r.ty) && lp == rp }, (BareFn(l), BareFn(r)) => { l.safety == r.safety diff --git a/src/tools/rustfmt/src/types.rs b/src/tools/rustfmt/src/types.rs index 7730aa467ce3a..5e7ea247f3b3d 100644 --- a/src/tools/rustfmt/src/types.rs +++ b/src/tools/rustfmt/src/types.rs @@ -729,7 +729,8 @@ impl Rewrite for ast::Ty { rewrite_unary_prefix(context, prefix, &*mt.ty, shape) } - ast::TyKind::Ref(ref lifetime, ref mt) => { + ast::TyKind::Ref(ref lifetime, _pinned, ref mt) => { + // FIXME: format pinnedness let mut_str = format_mutability(mt.mutbl); let mut_len = mut_str.len(); let mut result = String::with_capacity(128); @@ -1143,7 +1144,7 @@ pub(crate) fn can_be_overflowed_type( ) -> bool { match ty.kind { ast::TyKind::Tup(..) => context.use_block_indent() && len == 1, - ast::TyKind::Ref(_, ref mutty) | ast::TyKind::Ptr(ref mutty) => { + ast::TyKind::Ref(_, _, ref mutty) | ast::TyKind::Ptr(ref mutty) => { can_be_overflowed_type(context, &*mutty.ty, len) } _ => false, diff --git a/tests/ui/async-await/pin-sugar-ambiguity.rs b/tests/ui/async-await/pin-sugar-ambiguity.rs new file mode 100644 index 0000000000000..d183000931ec1 --- /dev/null +++ b/tests/ui/async-await/pin-sugar-ambiguity.rs @@ -0,0 +1,15 @@ +//@ check-pass +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +// Handle the case where there's ambiguity between pin as a contextual keyword and pin as a path. + +struct Foo; + +mod pin { + pub struct Foo; +} + +fn main() { + let _x: &pin ::Foo = &pin::Foo; +} diff --git a/tests/ui/async-await/pin-sugar-no-const.rs b/tests/ui/async-await/pin-sugar-no-const.rs new file mode 100644 index 0000000000000..dd6456b603481 --- /dev/null +++ b/tests/ui/async-await/pin-sugar-no-const.rs @@ -0,0 +1,8 @@ +#![feature(pin_ergonomics)] +#![allow(incomplete_features)] + +// Makes sure we don't accidentally accept `&pin Foo` without the `const` keyword. + +fn main() { + let _x: &pin i32 = todo!(); //~ ERROR found `i32` +} diff --git a/tests/ui/async-await/pin-sugar-no-const.stderr b/tests/ui/async-await/pin-sugar-no-const.stderr new file mode 100644 index 0000000000000..5f01156c1f0a4 --- /dev/null +++ b/tests/ui/async-await/pin-sugar-no-const.stderr @@ -0,0 +1,15 @@ +error: expected one of `!`, `(`, `::`, `;`, `<`, or `=`, found `i32` + --> $DIR/pin-sugar-no-const.rs:7:18 + | +LL | let _x: &pin i32 = todo!(); + | - ^^^ expected one of `!`, `(`, `::`, `;`, `<`, or `=` + | | + | while parsing the type for `_x` + | +help: there is a keyword `in` with a similar name + | +LL | let _x: &in i32 = todo!(); + | ~~ + +error: aborting due to 1 previous error + diff --git a/tests/ui/async-await/pin-sugar.rs b/tests/ui/async-await/pin-sugar.rs new file mode 100644 index 0000000000000..8dbdec418b1fa --- /dev/null +++ b/tests/ui/async-await/pin-sugar.rs @@ -0,0 +1,51 @@ +//@ check-pass + +#![feature(pin_ergonomics)] +#![allow(dead_code, incomplete_features)] + +// Makes sure we can handle `&pin mut T` and `&pin const T` as sugar for `Pin<&mut T>` and +// `Pin<&T>`. + +use std::pin::Pin; + +struct Foo; + +impl Foo { + fn baz(self: &pin mut Self) { + } + + fn baz_const(self: &pin const Self) { + } + + fn baz_lt<'a>(self: &'a pin mut Self) { + } + + fn baz_const_lt(self: &'_ pin const Self) { + } +} + +fn foo(_: &pin mut Foo) { +} + +fn foo_const(x: &pin const Foo) { +} + +fn bar(x: &pin mut Foo) { + foo(x); + foo(x); // for this to work we need to automatically reborrow, + // as if the user had written `foo(x.as_mut())`. + + 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 d694531d53abe..010bca388c10f 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.rs @@ -1,15 +1,16 @@ -#![allow(dead_code, incomplete_features)] +#![allow(dead_code)] use std::pin::Pin; struct Foo; -fn foo(_: Pin<&mut Foo>) { -} +fn foo(_: &pin mut Foo) {} //~ ERROR pinned reference syntax is experimental -fn bar(mut x: Pin<&mut Foo>) { +fn bar(x: Pin<&mut Foo>) { foo(x); foo(x); //~ ERROR use of moved value: `x` } +fn baz(_: &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 6c9029d817674..3443efd0486ec 100644 --- a/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr +++ b/tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr @@ -1,8 +1,28 @@ +error[E0658]: pinned reference syntax is experimental + --> $DIR/feature-gate-pin_ergonomics.rs:7:12 + | +LL | fn foo(_: &pin mut Foo) {} + | ^^^ + | + = note: see issue #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:14:12 + | +LL | fn baz(_: &pin const Foo) {} + | ^^^ + | + = note: see issue #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:12:9 + --> $DIR/feature-gate-pin_ergonomics.rs:11:9 | -LL | fn bar(mut x: Pin<&mut Foo>) { - | ----- move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait +LL | fn bar(x: Pin<&mut Foo>) { + | - move occurs because `x` has type `Pin<&mut Foo>`, which does not implement the `Copy` trait LL | foo(x); | - value moved here LL | foo(x); @@ -11,11 +31,12 @@ LL | foo(x); 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:7:11 | -LL | fn foo(_: Pin<&mut Foo>) { - | --- ^^^^^^^^^^^^^ this parameter takes ownership of the value +LL | fn foo(_: &pin mut Foo) {} + | --- ^^^^^^^^^^^^ this parameter takes ownership of the value | | | in this function -error: aborting due to 1 previous error +error: aborting due to 3 previous errors -For more information about this error, try `rustc --explain E0382`. +Some errors have detailed explanations: E0382, E0658. +For more information about an error, try `rustc --explain E0382`.