Rollup merge of #130526 - eholk:pin-reborrow, r=compiler-errors
Begin experimental support for pin reborrowing This commit adds basic support for reborrowing `Pin` types in argument position. At the moment it only supports reborrowing `Pin<&mut T>` as `Pin<&mut T>` by inserting a call to `Pin::as_mut()`, and only in argument position (not as the receiver in a method call). This PR makes the following example compile: ```rust #![feature(pin_ergonomics)] fn foo(_: Pin<&mut Foo>) { } fn bar(mut x: Pin<&mut Foo>) { foo(x); foo(x); } ``` Previously, you would have had to write `bar` as: ```rust fn bar(mut x: Pin<&mut Foo>) { foo(x.as_mut()); foo(x); } ``` Tracking: - #130494 r? `@compiler-errors`
This commit is contained in:
commit
fe5f734e6a
@ -207,7 +207,7 @@ borrowck_simd_intrinsic_arg_const =
|
|||||||
*[other] {$arg}th
|
*[other] {$arg}th
|
||||||
} argument of `{$intrinsic}` is required to be a `const` item
|
} argument of `{$intrinsic}` is required to be a `const` item
|
||||||
|
|
||||||
borrowck_suggest_create_freash_reborrow =
|
borrowck_suggest_create_fresh_reborrow =
|
||||||
consider reborrowing the `Pin` instead of moving it
|
consider reborrowing the `Pin` instead of moving it
|
||||||
|
|
||||||
borrowck_suggest_iterate_over_slice =
|
borrowck_suggest_iterate_over_slice =
|
||||||
|
@ -415,7 +415,7 @@ pub(crate) enum CaptureReasonSuggest<'tcx> {
|
|||||||
span: Span,
|
span: Span,
|
||||||
},
|
},
|
||||||
#[suggestion(
|
#[suggestion(
|
||||||
borrowck_suggest_create_freash_reborrow,
|
borrowck_suggest_create_fresh_reborrow,
|
||||||
applicability = "maybe-incorrect",
|
applicability = "maybe-incorrect",
|
||||||
code = ".as_mut()",
|
code = ".as_mut()",
|
||||||
style = "verbose"
|
style = "verbose"
|
||||||
|
@ -558,6 +558,8 @@ pub fn internal(&self, feature: Symbol) -> bool {
|
|||||||
(unstable, optimize_attribute, "1.34.0", Some(54882)),
|
(unstable, optimize_attribute, "1.34.0", Some(54882)),
|
||||||
/// Allows specifying nop padding on functions for dynamic patching.
|
/// Allows specifying nop padding on functions for dynamic patching.
|
||||||
(unstable, patchable_function_entry, "1.81.0", Some(123115)),
|
(unstable, patchable_function_entry, "1.81.0", Some(123115)),
|
||||||
|
/// Experimental features that make `Pin` more ergonomic.
|
||||||
|
(incomplete, pin_ergonomics, "CURRENT_RUSTC_VERSION", Some(130494)),
|
||||||
/// Allows postfix match `expr.match { ... }`
|
/// Allows postfix match `expr.match { ... }`
|
||||||
(unstable, postfix_match, "1.79.0", Some(121618)),
|
(unstable, postfix_match, "1.79.0", Some(121618)),
|
||||||
/// Allows macro attributes on expressions, statements and non-inline modules.
|
/// Allows macro attributes on expressions, statements and non-inline modules.
|
||||||
|
@ -214,6 +214,12 @@ fn coerce(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
|||||||
ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => {
|
ty::Dynamic(predicates, region, ty::DynStar) if self.tcx.features().dyn_star => {
|
||||||
return self.coerce_dyn_star(a, b, predicates, region);
|
return self.coerce_dyn_star(a, b, predicates, region);
|
||||||
}
|
}
|
||||||
|
ty::Adt(pin, _)
|
||||||
|
if self.tcx.features().pin_ergonomics
|
||||||
|
&& self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) =>
|
||||||
|
{
|
||||||
|
return self.coerce_pin(a, b);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -774,6 +780,62 @@ fn coerce_dyn_star(
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Applies reborrowing for `Pin`
|
||||||
|
///
|
||||||
|
/// We currently only support reborrowing `Pin<&mut T>` as `Pin<&mut T>`. This is accomplished
|
||||||
|
/// by inserting a call to `Pin::as_mut` during MIR building.
|
||||||
|
///
|
||||||
|
/// In the future we might want to support other reborrowing coercions, such as:
|
||||||
|
/// - `Pin<&mut T>` as `Pin<&T>`
|
||||||
|
/// - `Pin<&T>` as `Pin<&T>`
|
||||||
|
/// - `Pin<Box<T>>` as `Pin<&T>`
|
||||||
|
/// - `Pin<Box<T>>` as `Pin<&mut T>`
|
||||||
|
#[instrument(skip(self), level = "trace")]
|
||||||
|
fn coerce_pin(&self, a: Ty<'tcx>, b: Ty<'tcx>) -> CoerceResult<'tcx> {
|
||||||
|
// We need to make sure the two types are compatible for coercion.
|
||||||
|
// Then we will build a ReborrowPin adjustment and return that as an InferOk.
|
||||||
|
|
||||||
|
// Right now we can only reborrow if this is a `Pin<&mut T>`.
|
||||||
|
let extract_pin_mut = |ty: Ty<'tcx>| {
|
||||||
|
// Get the T out of Pin<T>
|
||||||
|
let (pin, ty) = match ty.kind() {
|
||||||
|
ty::Adt(pin, args) if self.tcx.is_lang_item(pin.did(), hir::LangItem::Pin) => {
|
||||||
|
(*pin, args[0].expect_ty())
|
||||||
|
}
|
||||||
|
_ => {
|
||||||
|
debug!("can't reborrow {:?} as pinned", ty);
|
||||||
|
return Err(TypeError::Mismatch);
|
||||||
|
}
|
||||||
|
};
|
||||||
|
// Make sure the T is something we understand (just `&mut U` for now)
|
||||||
|
match ty.kind() {
|
||||||
|
ty::Ref(region, ty, mutbl) => Ok((pin, *region, *ty, *mutbl)),
|
||||||
|
_ => {
|
||||||
|
debug!("can't reborrow pin of inner type {:?}", ty);
|
||||||
|
Err(TypeError::Mismatch)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
};
|
||||||
|
|
||||||
|
let (pin, a_region, a_ty, mut_a) = extract_pin_mut(a)?;
|
||||||
|
let (_, b_region, _b_ty, mut_b) = extract_pin_mut(b)?;
|
||||||
|
|
||||||
|
coerce_mutbls(mut_a, mut_b)?;
|
||||||
|
|
||||||
|
// update a with b's mutability since we'll be coercing mutability
|
||||||
|
let a = Ty::new_adt(
|
||||||
|
self.tcx,
|
||||||
|
pin,
|
||||||
|
self.tcx.mk_args(&[Ty::new_ref(self.tcx, a_region, a_ty, mut_b).into()]),
|
||||||
|
);
|
||||||
|
|
||||||
|
// To complete the reborrow, we need to make sure we can unify the inner types, and if so we
|
||||||
|
// add the adjustments.
|
||||||
|
self.unify_and(a, b, |_inner_ty| {
|
||||||
|
vec![Adjustment { kind: Adjust::ReborrowPin(b_region, mut_b), target: b }]
|
||||||
|
})
|
||||||
|
}
|
||||||
|
|
||||||
fn coerce_from_safe_fn<F, G>(
|
fn coerce_from_safe_fn<F, G>(
|
||||||
&self,
|
&self,
|
||||||
a: Ty<'tcx>,
|
a: Ty<'tcx>,
|
||||||
|
@ -780,6 +780,16 @@ fn walk_adjustment(&self, expr: &hir::Expr<'_>) -> Result<(), Cx::Error> {
|
|||||||
adjustment::Adjust::Borrow(ref autoref) => {
|
adjustment::Adjust::Borrow(ref autoref) => {
|
||||||
self.walk_autoref(expr, &place_with_id, autoref);
|
self.walk_autoref(expr, &place_with_id, autoref);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
adjustment::Adjust::ReborrowPin(_, mutbl) => {
|
||||||
|
// Reborrowing a Pin is like a combinations of a deref and a borrow, so we do
|
||||||
|
// both.
|
||||||
|
let bk = match mutbl {
|
||||||
|
ty::Mutability::Not => ty::BorrowKind::ImmBorrow,
|
||||||
|
ty::Mutability::Mut => ty::BorrowKind::MutBorrow,
|
||||||
|
};
|
||||||
|
self.delegate.borrow_mut().borrow(&place_with_id, place_with_id.hir_id, bk);
|
||||||
|
}
|
||||||
}
|
}
|
||||||
place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?;
|
place_with_id = self.cat_expr_adjusted(expr, place_with_id, adjustment)?;
|
||||||
}
|
}
|
||||||
@ -1284,6 +1294,7 @@ fn cat_expr_adjusted_with<F>(
|
|||||||
adjustment::Adjust::NeverToAny
|
adjustment::Adjust::NeverToAny
|
||||||
| adjustment::Adjust::Pointer(_)
|
| adjustment::Adjust::Pointer(_)
|
||||||
| adjustment::Adjust::Borrow(_)
|
| adjustment::Adjust::Borrow(_)
|
||||||
|
| adjustment::Adjust::ReborrowPin(..)
|
||||||
| adjustment::Adjust::DynStar => {
|
| adjustment::Adjust::DynStar => {
|
||||||
// Result is an rvalue.
|
// Result is an rvalue.
|
||||||
Ok(self.cat_rvalue(expr.hir_id, target))
|
Ok(self.cat_rvalue(expr.hir_id, target))
|
||||||
|
@ -104,6 +104,9 @@ pub enum Adjust<'tcx> {
|
|||||||
|
|
||||||
/// Cast into a dyn* object.
|
/// Cast into a dyn* object.
|
||||||
DynStar,
|
DynStar,
|
||||||
|
|
||||||
|
/// Take a pinned reference and reborrow as a `Pin<&mut T>` or `Pin<&T>`.
|
||||||
|
ReborrowPin(ty::Region<'tcx>, hir::Mutability),
|
||||||
}
|
}
|
||||||
|
|
||||||
/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
|
/// An overloaded autoderef step, representing a `Deref(Mut)::deref(_mut)`
|
||||||
|
@ -74,6 +74,7 @@ pub(super) fn mirror_expr_inner(&mut self, hir_expr: &'tcx hir::Expr<'tcx>) -> E
|
|||||||
self.thir.exprs.push(expr)
|
self.thir.exprs.push(expr)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[instrument(level = "trace", skip(self, expr, span))]
|
||||||
fn apply_adjustment(
|
fn apply_adjustment(
|
||||||
&mut self,
|
&mut self,
|
||||||
hir_expr: &'tcx hir::Expr<'tcx>,
|
hir_expr: &'tcx hir::Expr<'tcx>,
|
||||||
@ -146,6 +147,67 @@ fn apply_adjustment(
|
|||||||
ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) }
|
ExprKind::RawBorrow { mutability, arg: self.thir.exprs.push(expr) }
|
||||||
}
|
}
|
||||||
Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) },
|
Adjust::DynStar => ExprKind::Cast { source: self.thir.exprs.push(expr) },
|
||||||
|
Adjust::ReborrowPin(region, mutbl) => {
|
||||||
|
debug!("apply ReborrowPin adjustment");
|
||||||
|
// Rewrite `$expr` as `Pin { __pointer: &(mut)? *($expr).__pointer }`
|
||||||
|
|
||||||
|
// We'll need these types later on
|
||||||
|
let pin_ty_args = match expr.ty.kind() {
|
||||||
|
ty::Adt(_, args) => args,
|
||||||
|
_ => bug!("ReborrowPin with non-Pin type"),
|
||||||
|
};
|
||||||
|
let pin_ty = pin_ty_args.iter().next().unwrap().expect_ty();
|
||||||
|
let ptr_target_ty = match pin_ty.kind() {
|
||||||
|
ty::Ref(_, ty, _) => *ty,
|
||||||
|
_ => bug!("ReborrowPin with non-Ref type"),
|
||||||
|
};
|
||||||
|
|
||||||
|
// pointer = ($expr).__pointer
|
||||||
|
let pointer_target = ExprKind::Field {
|
||||||
|
lhs: self.thir.exprs.push(expr),
|
||||||
|
variant_index: FIRST_VARIANT,
|
||||||
|
name: FieldIdx::from(0u32),
|
||||||
|
};
|
||||||
|
let arg = Expr { temp_lifetime, ty: pin_ty, span, kind: pointer_target };
|
||||||
|
let arg = self.thir.exprs.push(arg);
|
||||||
|
|
||||||
|
// arg = *pointer
|
||||||
|
let expr = ExprKind::Deref { arg };
|
||||||
|
let arg = self.thir.exprs.push(Expr {
|
||||||
|
temp_lifetime,
|
||||||
|
ty: ptr_target_ty,
|
||||||
|
span,
|
||||||
|
kind: expr,
|
||||||
|
});
|
||||||
|
|
||||||
|
// expr = &mut target
|
||||||
|
let borrow_kind = match mutbl {
|
||||||
|
hir::Mutability::Mut => BorrowKind::Mut { kind: mir::MutBorrowKind::Default },
|
||||||
|
hir::Mutability::Not => BorrowKind::Shared,
|
||||||
|
};
|
||||||
|
let new_pin_target = Ty::new_ref(self.tcx, region, ptr_target_ty, mutbl);
|
||||||
|
let expr = self.thir.exprs.push(Expr {
|
||||||
|
temp_lifetime,
|
||||||
|
ty: new_pin_target,
|
||||||
|
span,
|
||||||
|
kind: ExprKind::Borrow { borrow_kind, arg },
|
||||||
|
});
|
||||||
|
|
||||||
|
// kind = Pin { __pointer: pointer }
|
||||||
|
let pin_did = self.tcx.require_lang_item(rustc_hir::LangItem::Pin, Some(span));
|
||||||
|
let args = self.tcx.mk_args(&[new_pin_target.into()]);
|
||||||
|
let kind = ExprKind::Adt(Box::new(AdtExpr {
|
||||||
|
adt_def: self.tcx.adt_def(pin_did),
|
||||||
|
variant_index: FIRST_VARIANT,
|
||||||
|
args,
|
||||||
|
fields: Box::new([FieldExpr { name: FieldIdx::from(0u32), expr }]),
|
||||||
|
user_ty: None,
|
||||||
|
base: None,
|
||||||
|
}));
|
||||||
|
|
||||||
|
debug!(?kind);
|
||||||
|
kind
|
||||||
|
}
|
||||||
};
|
};
|
||||||
|
|
||||||
Expr { temp_lifetime, ty: adjustment.target, span, kind }
|
Expr { temp_lifetime, ty: adjustment.target, span, kind }
|
||||||
@ -1014,7 +1076,7 @@ fn overloaded_place(
|
|||||||
|
|
||||||
// Reconstruct the output assuming it's a reference with the
|
// Reconstruct the output assuming it's a reference with the
|
||||||
// same region and mutability as the receiver. This holds for
|
// same region and mutability as the receiver. This holds for
|
||||||
// `Deref(Mut)::Deref(_mut)` and `Index(Mut)::index(_mut)`.
|
// `Deref(Mut)::deref(_mut)` and `Index(Mut)::index(_mut)`.
|
||||||
let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else {
|
let ty::Ref(region, _, mutbl) = *self.thir[args[0]].ty.kind() else {
|
||||||
span_bug!(span, "overloaded_place: receiver is not a reference");
|
span_bug!(span, "overloaded_place: receiver is not a reference");
|
||||||
};
|
};
|
||||||
|
@ -1453,6 +1453,7 @@
|
|||||||
pic,
|
pic,
|
||||||
pie,
|
pie,
|
||||||
pin,
|
pin,
|
||||||
|
pin_ergonomics,
|
||||||
platform_intrinsics,
|
platform_intrinsics,
|
||||||
plugin,
|
plugin,
|
||||||
plugin_registrar,
|
plugin_registrar,
|
||||||
|
36
tests/ui/async-await/pin-reborrow-arg.rs
Normal file
36
tests/ui/async-await/pin-reborrow-arg.rs
Normal file
@ -0,0 +1,36 @@
|
|||||||
|
//@ check-pass
|
||||||
|
|
||||||
|
#![feature(pin_ergonomics)]
|
||||||
|
#![allow(dead_code, incomplete_features)]
|
||||||
|
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
fn baz(self: Pin<&mut Self>) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo(_: Pin<&mut Foo>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn foo_const(_: Pin<&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);
|
||||||
|
|
||||||
|
foo_const(x); // make sure we can reborrow &mut as &.
|
||||||
|
|
||||||
|
let x: Pin<&Foo> = Pin::new(&Foo);
|
||||||
|
|
||||||
|
foo_const(x); // make sure reborrowing from & to & works.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
18
tests/ui/async-await/pin-reborrow-const-as-mut.rs
Normal file
18
tests/ui/async-await/pin-reborrow-const-as-mut.rs
Normal file
@ -0,0 +1,18 @@
|
|||||||
|
#![feature(pin_ergonomics)]
|
||||||
|
#![allow(dead_code, incomplete_features)]
|
||||||
|
|
||||||
|
// make sure we can't accidentally reborrow Pin<&T> as Pin<&mut T>
|
||||||
|
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
fn foo(_: Pin<&mut Foo>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar(x: Pin<&Foo>) {
|
||||||
|
foo(x); //~ ERROR mismatched types
|
||||||
|
//| ERROR types differ in mutability
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
19
tests/ui/async-await/pin-reborrow-const-as-mut.stderr
Normal file
19
tests/ui/async-await/pin-reborrow-const-as-mut.stderr
Normal file
@ -0,0 +1,19 @@
|
|||||||
|
error[E0308]: mismatched types
|
||||||
|
--> $DIR/pin-reborrow-const-as-mut.rs:14:9
|
||||||
|
|
|
||||||
|
LL | foo(x);
|
||||||
|
| --- ^ types differ in mutability
|
||||||
|
| |
|
||||||
|
| arguments to this function are incorrect
|
||||||
|
|
|
||||||
|
= note: expected struct `Pin<&mut Foo>`
|
||||||
|
found struct `Pin<&Foo>`
|
||||||
|
note: function defined here
|
||||||
|
--> $DIR/pin-reborrow-const-as-mut.rs:10:4
|
||||||
|
|
|
||||||
|
LL | fn foo(_: Pin<&mut Foo>) {
|
||||||
|
| ^^^ ----------------
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0308`.
|
13
tests/ui/async-await/pin-reborrow-once.rs
Normal file
13
tests/ui/async-await/pin-reborrow-once.rs
Normal file
@ -0,0 +1,13 @@
|
|||||||
|
#![feature(pin_ergonomics)]
|
||||||
|
#![allow(dead_code, incomplete_features)]
|
||||||
|
|
||||||
|
// Make sure with pin reborrowing that we can only get one mutable reborrow of a pinned reference.
|
||||||
|
|
||||||
|
use std::pin::{pin, Pin};
|
||||||
|
|
||||||
|
fn twice(_: Pin<&mut i32>, _: Pin<&mut i32>) {}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
let x = pin!(42);
|
||||||
|
twice(x, x); //~ ERROR cannot borrow
|
||||||
|
}
|
12
tests/ui/async-await/pin-reborrow-once.stderr
Normal file
12
tests/ui/async-await/pin-reborrow-once.stderr
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
error[E0499]: cannot borrow `*x.__pointer` as mutable more than once at a time
|
||||||
|
--> $DIR/pin-reborrow-once.rs:12:14
|
||||||
|
|
|
||||||
|
LL | twice(x, x);
|
||||||
|
| ----- - ^ second mutable borrow occurs here
|
||||||
|
| | |
|
||||||
|
| | first mutable borrow occurs here
|
||||||
|
| first borrow later used by call
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0499`.
|
24
tests/ui/async-await/pin-reborrow-self.rs
Normal file
24
tests/ui/async-await/pin-reborrow-self.rs
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
//@ check-pass
|
||||||
|
//@ignore-test
|
||||||
|
|
||||||
|
// Currently ignored due to self reborrowing not being implemented for Pin
|
||||||
|
|
||||||
|
#![feature(pin_ergonomics)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
impl Foo {
|
||||||
|
fn foo(self: Pin<&mut Self>) {
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar(x: Pin<&mut Foo>) {
|
||||||
|
x.foo();
|
||||||
|
x.foo(); // for this to work we need to automatically reborrow,
|
||||||
|
// as if the user had written `x.as_mut().foo()`.
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
14
tests/ui/async-await/pin-reborrow-shorter.rs
Normal file
14
tests/ui/async-await/pin-reborrow-shorter.rs
Normal file
@ -0,0 +1,14 @@
|
|||||||
|
//@check-pass
|
||||||
|
|
||||||
|
#![feature(pin_ergonomics)]
|
||||||
|
#![allow(dead_code, incomplete_features)]
|
||||||
|
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
fn shorter<'b, T: 'b>(_: Pin<&'b mut T>) {}
|
||||||
|
|
||||||
|
fn test<'a: 'b, 'b, T: 'a>(x: Pin<&'a mut T>) {
|
||||||
|
shorter::<'b>(x);
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
15
tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
Normal file
15
tests/ui/feature-gates/feature-gate-pin_ergonomics.rs
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
#![allow(dead_code, incomplete_features)]
|
||||||
|
|
||||||
|
use std::pin::Pin;
|
||||||
|
|
||||||
|
struct Foo;
|
||||||
|
|
||||||
|
fn foo(_: Pin<&mut Foo>) {
|
||||||
|
}
|
||||||
|
|
||||||
|
fn bar(mut x: Pin<&mut Foo>) {
|
||||||
|
foo(x);
|
||||||
|
foo(x); //~ ERROR use of moved value: `x`
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {}
|
21
tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
Normal file
21
tests/ui/feature-gates/feature-gate-pin_ergonomics.stderr
Normal file
@ -0,0 +1,21 @@
|
|||||||
|
error[E0382]: use of moved value: `x`
|
||||||
|
--> $DIR/feature-gate-pin_ergonomics.rs:12: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 | foo(x);
|
||||||
|
| - value moved here
|
||||||
|
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:7:11
|
||||||
|
|
|
||||||
|
LL | fn foo(_: Pin<&mut Foo>) {
|
||||||
|
| --- ^^^^^^^^^^^^^ this parameter takes ownership of the value
|
||||||
|
| |
|
||||||
|
| in this function
|
||||||
|
|
||||||
|
error: aborting due to 1 previous error
|
||||||
|
|
||||||
|
For more information about this error, try `rustc --explain E0382`.
|
Loading…
Reference in New Issue
Block a user