about summary refs log tree commit diff
diff options
context:
space:
mode:
-rw-r--r--compiler/rustc_mir_build/src/thir/cx/expr.rs38
-rw-r--r--tests/pretty/pin-ergonomics-hir.pp3
-rw-r--r--tests/pretty/pin-ergonomics.rs1
-rw-r--r--tests/ui/pin-ergonomics/borrow-mut-xor-share.rs59
-rw-r--r--tests/ui/pin-ergonomics/borrow-mut-xor-share.stderr121
-rw-r--r--tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr238
-rw-r--r--tests/ui/pin-ergonomics/borrow-unpin.rs143
-rw-r--r--tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr136
-rw-r--r--tests/ui/pin-ergonomics/borrow.rs11
9 files changed, 559 insertions, 191 deletions
diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs
index 52de0395ab6..764b7efe2a3 100644
--- a/compiler/rustc_mir_build/src/thir/cx/expr.rs
+++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs
@@ -480,15 +480,39 @@ impl<'tcx> ThirBuildCx<'tcx> {
             }
 
             // 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);
+            // `Pin { __pointer: &mut { $expr } }` and `Pin { __pointer: &$expr }`.
+            hir::ExprKind::AddrOf(hir::BorrowKind::Pin, mutbl, arg_expr) => match expr_ty.kind() {
+                &ty::Adt(adt_def, args) if tcx.is_lang_item(adt_def.did(), hir::LangItem::Pin) => {
+                    let ty = args.type_at(0);
+                    let arg_ty = self.typeck_results.expr_ty(arg_expr);
+                    let mut arg = self.mirror_expr(arg_expr);
+                    // For `&pin mut $place` where `$place` is not `Unpin`, move the place
+                    // `$place` to ensure it will not be used afterwards.
+                    if mutbl.is_mut() && !arg_ty.is_unpin(self.tcx, self.typing_env) {
+                        let block = self.thir.blocks.push(Block {
+                            targeted_by_break: false,
+                            region_scope: region::Scope {
+                                local_id: arg_expr.hir_id.local_id,
+                                data: region::ScopeData::Node,
+                            },
+                            span: arg_expr.span,
+                            stmts: Box::new([]),
+                            expr: Some(arg),
+                            safety_mode: BlockSafety::Safe,
+                        });
+                        let (temp_lifetime, backwards_incompatible) = self
+                            .rvalue_scopes
+                            .temporary_scope(self.region_scope_tree, arg_expr.hir_id.local_id);
+                        arg = self.thir.exprs.push(Expr {
+                            temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
+                            ty: arg_ty,
+                            span: arg_expr.span,
+                            kind: ExprKind::Block { block },
+                        });
+                    }
                     let expr = self.thir.exprs.push(Expr {
                         temp_lifetime: TempLifetime { temp_lifetime, backwards_incompatible },
-                        ty: args.type_at(0),
+                        ty,
                         span: expr.span,
                         kind: ExprKind::Borrow { borrow_kind: mutbl.to_borrow_kind(), arg },
                     });
diff --git a/tests/pretty/pin-ergonomics-hir.pp b/tests/pretty/pin-ergonomics-hir.pp
index 42405982f92..212e0e174da 100644
--- a/tests/pretty/pin-ergonomics-hir.pp
+++ b/tests/pretty/pin-ergonomics-hir.pp
@@ -2,7 +2,8 @@
 //@ pretty-mode:hir
 //@ pp-exact:pin-ergonomics-hir.pp
 
-#![feature(pin_ergonomics)]#![allow(dead_code, incomplete_features)]
+#![feature(pin_ergonomics)]
+#![allow(dead_code, incomplete_features)]
 #[prelude_import]
 use ::std::prelude::rust_2015::*;
 #[macro_use]
diff --git a/tests/pretty/pin-ergonomics.rs b/tests/pretty/pin-ergonomics.rs
index 54a57545c55..8e8ced791b1 100644
--- a/tests/pretty/pin-ergonomics.rs
+++ b/tests/pretty/pin-ergonomics.rs
@@ -30,7 +30,6 @@ fn bar() {
     foo_const(x);
 
     let x: Pin<&_> = &pin const Foo;
-
     foo_const(x);
     foo_const(x);
 }
diff --git a/tests/ui/pin-ergonomics/borrow-mut-xor-share.rs b/tests/ui/pin-ergonomics/borrow-mut-xor-share.rs
deleted file mode 100644
index c5363eafef5..00000000000
--- a/tests/ui/pin-ergonomics/borrow-mut-xor-share.rs
+++ /dev/null
@@ -1,59 +0,0 @@
-#![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/pin-ergonomics/borrow-mut-xor-share.stderr b/tests/ui/pin-ergonomics/borrow-mut-xor-share.stderr
deleted file mode 100644
index 47d990b2ec9..00000000000
--- a/tests/ui/pin-ergonomics/borrow-mut-xor-share.stderr
+++ /dev/null
@@ -1,121 +0,0 @@
-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/pin-ergonomics/borrow-unpin.pinned.stderr b/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr
new file mode 100644
index 00000000000..cc438461a5d
--- /dev/null
+++ b/tests/ui/pin-ergonomics/borrow-unpin.pinned.stderr
@@ -0,0 +1,238 @@
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:39:14
+   |
+LL |     let foo = Foo::default();
+   |         --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo_pin_mut(&pin mut foo);
+   |                          --- value moved here
+LL |     foo_move(foo);
+   |              ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     foo_pin_mut(&pin mut foo);
+   |                          --- you could clone this value
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:43:14
+   |
+LL |     let foo = Foo::default();
+   |         --- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     let x = &pin mut foo;
+   |                      --- value moved here
+LL |     foo_move(foo);
+   |              ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo;
+   |                      --- you could clone this value
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:52:14
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- value moved here
+LL |     foo_move(foo);
+   |              ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- you could clone this value
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:56:14
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     let x = &pin mut foo; // ok
+   |                      --- value moved here
+LL |     foo_move(foo);
+   |              ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo; // ok
+   |                      --- you could clone this value
+
+error[E0505]: cannot move out of `foo` because it is borrowed
+  --> $DIR/borrow-unpin.rs:68:14
+   |
+LL |     let foo = Foo::default();
+   |         --- binding `foo` declared here
+LL |     let x = &pin const foo; // ok
+   |             -------------- borrow of `foo` occurs here
+LL |     foo_move(foo);
+   |              ^^^ move out of `foo` occurs here
+LL |
+LL |     foo_pin_ref(x);
+   |                 - borrow later used here
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin const foo; // ok
+   |                        --- you could clone this value
+
+error[E0382]: borrow of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:76:13
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- value moved here
+LL |     foo_ref(&foo);
+   |             ^^^^ value borrowed here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- you could clone this value
+
+error[E0382]: borrow of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:80:13
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     let x = &pin mut foo; // ok
+   |                      --- value moved here
+LL |     foo_ref(&foo);
+   |             ^^^^ value borrowed here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo; // ok
+   |                      --- you could clone this value
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:99:26
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- value moved here
+LL |     foo_pin_mut(&pin mut foo);
+   |                          ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- you could clone this value
+
+error[E0382]: use of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:103:26
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     let x = &pin mut foo; // ok
+   |                      --- value moved here
+LL |     foo_pin_mut(&pin mut foo);
+   |                          ^^^ value used here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo; // ok
+   |                      --- you could clone this value
+
+error[E0505]: cannot move out of `foo` because it is borrowed
+  --> $DIR/borrow-unpin.rs:115:26
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- binding `foo` declared here
+LL |     let x = &pin const foo; // ok
+   |             -------------- borrow of `foo` occurs here
+LL |     foo_pin_mut(&pin mut foo);
+   |                          ^^^ move out of `foo` occurs here
+LL |
+LL |     foo_pin_ref(x);
+   |                 - borrow later used here
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin const foo; // ok
+   |                        --- you could clone this value
+
+error[E0382]: borrow of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:123:17
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- value moved here
+LL |     foo_pin_ref(&pin const foo);
+   |                 ^^^^^^^^^^^^^^ value borrowed here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     foo_pin_mut(&pin mut foo); // ok
+   |                          --- you could clone this value
+
+error[E0382]: borrow of moved value: `foo`
+  --> $DIR/borrow-unpin.rs:127:17
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- move occurs because `foo` has type `Foo`, which does not implement the `Copy` trait
+LL |     let x = &pin mut foo; // ok
+   |                      --- value moved here
+LL |     foo_pin_ref(&pin const foo);
+   |                 ^^^^^^^^^^^^^^ value borrowed here after move
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:16:1
+   |
+LL | struct Foo(PhantomPinned);
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo; // ok
+   |                      --- you could clone this value
+
+error: aborting due to 12 previous errors
+
+Some errors have detailed explanations: E0382, E0505.
+For more information about an error, try `rustc --explain E0382`.
diff --git a/tests/ui/pin-ergonomics/borrow-unpin.rs b/tests/ui/pin-ergonomics/borrow-unpin.rs
new file mode 100644
index 00000000000..61e69bab12b
--- /dev/null
+++ b/tests/ui/pin-ergonomics/borrow-unpin.rs
@@ -0,0 +1,143 @@
+//@ revisions: unpin pinned
+#![feature(pin_ergonomics)]
+#![allow(dead_code, incomplete_features)]
+
+// For now, in order to ensure soundness, we move the place in `&pin mut place`
+// if `place` is not `Unpin`.
+// In the next step, we borrow the place instead of moving it, after that we
+// have to makes sure `&pin mut place` and `&pin const place` cannot violate
+// the mut-xor-share rules.
+
+use std::pin::Pin;
+use std::marker::PhantomPinned;
+
+#[cfg(pinned)]
+#[derive(Default)]
+struct Foo(PhantomPinned);
+
+#[cfg(unpin)]
+#[derive(Default)]
+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 foo_move(_: Foo) {}
+
+fn immutable_pin_mut_then_move() {
+    let foo = Foo::default();
+    foo_pin_mut(&pin mut foo); //[unpin]~ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable
+    foo_move(foo); //[pinned]~ ERROR use of moved value: `foo`
+
+    let foo = Foo::default();
+    let x = &pin mut foo; //[unpin]~ ERROR cannot borrow `foo` as mutable, as it is not declared as mutable
+    foo_move(foo); //[pinned]~ ERROR use of moved value: `foo`
+    //[unpin]~^ ERROR cannot move out of `foo` because it is borrowed
+    foo_pin_mut(x); //
+}
+
+
+fn pin_mut_then_move() {
+    let mut foo = Foo::default();
+    foo_pin_mut(&pin mut foo); // ok
+    foo_move(foo); //[pinned]~ ERROR use of moved value: `foo`
+
+    let mut foo = Foo::default();
+    let x = &pin mut foo; // ok
+    foo_move(foo); //[pinned]~ ERROR use of moved value: `foo`
+    //[unpin]~^ ERROR cannot move out of `foo` because it is borrowed
+    foo_pin_mut(x); //
+}
+
+fn pin_ref_then_move() {
+    let foo = Foo::default();
+    foo_pin_ref(&pin const foo); // ok
+    foo_move(foo); // ok
+
+    let foo = Foo::default();
+    let x = &pin const foo; // ok
+    foo_move(foo); //[pinned]~ ERROR cannot move out of `foo` because it is borrowed
+    //[unpin]~^ ERROR cannot move out of `foo` because it is borrowed
+    foo_pin_ref(x);
+}
+
+fn pin_mut_then_ref() {
+    let mut foo = Foo::default();
+    foo_pin_mut(&pin mut foo); // ok
+    foo_ref(&foo); //[pinned]~ ERROR borrow of moved value: `foo`
+
+    let mut foo = Foo::default();
+    let x = &pin mut foo; // ok
+    foo_ref(&foo); //[pinned]~ ERROR borrow of moved value: `foo`
+    //[unpin]~^ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
+    foo_pin_mut(x);
+}
+
+fn pin_ref_then_ref() {
+    let mut foo = Foo::default();
+    foo_pin_ref(&pin const foo); // ok
+    foo_ref(&foo); // ok
+
+    let mut foo = Foo::default();
+    let x = &pin const foo; // ok
+    foo_ref(&foo); // ok
+    foo_pin_ref(x);
+}
+
+fn pin_mut_then_pin_mut() {
+    let mut foo = Foo::default();
+    foo_pin_mut(&pin mut foo); // ok
+    foo_pin_mut(&pin mut foo); //[pinned]~ ERROR use of moved value: `foo`
+
+    let mut foo = Foo::default();
+    let x = &pin mut foo; // ok
+    foo_pin_mut(&pin mut foo); //[pinned]~ ERROR use of moved value: `foo`
+    //[unpin]~^ ERROR cannot borrow `foo` as mutable more than once at a time
+    foo_pin_mut(x);
+}
+
+fn pin_ref_then_pin_mut() {
+    let mut foo = Foo::default();
+    foo_pin_ref(&pin const foo); // ok
+    foo_pin_mut(&pin mut foo); // ok
+
+    let mut foo = Foo::default();
+    let x = &pin const foo; // ok
+    foo_pin_mut(&pin mut foo); //[pinned]~ ERROR cannot move out of `foo` because it is borrowed
+    //[unpin]~^ ERROR cannot borrow `foo` as mutable because it is also borrowed as immutable
+    foo_pin_ref(x);
+}
+
+fn pin_mut_then_pin_ref() {
+    let mut foo = Foo::default();
+    foo_pin_mut(&pin mut foo); // ok
+    foo_pin_ref(&pin const foo); //[pinned]~ ERROR borrow of moved value: `foo`
+
+    let mut foo = Foo::default();
+    let x = &pin mut foo; // ok
+    foo_pin_ref(&pin const foo); //[pinned]~ ERROR borrow of moved value: `foo`
+    //[unpin]~^ ERROR cannot borrow `foo` as immutable because it is also borrowed as mutable
+    foo_pin_mut(x);
+}
+
+fn pin_ref_then_pin_ref() {
+    let mut foo = Foo::default();
+    foo_pin_ref(&pin const foo); // ok
+    foo_pin_ref(&pin const foo); // ok
+
+    let mut foo = Foo::default();
+    let x = &pin const foo; // ok
+    foo_pin_ref(&pin const foo); // ok
+    foo_pin_ref(x);
+}
+
+fn main() {}
diff --git a/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr b/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr
new file mode 100644
index 00000000000..bf9921343ee
--- /dev/null
+++ b/tests/ui/pin-ergonomics/borrow-unpin.unpin.stderr
@@ -0,0 +1,136 @@
+error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable
+  --> $DIR/borrow-unpin.rs:38:17
+   |
+LL |     foo_pin_mut(&pin mut foo);
+   |                 ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut foo = Foo::default();
+   |         +++
+
+error[E0596]: cannot borrow `foo` as mutable, as it is not declared as mutable
+  --> $DIR/borrow-unpin.rs:42:13
+   |
+LL |     let x = &pin mut foo;
+   |             ^^^^^^^^^^^^ cannot borrow as mutable
+   |
+help: consider changing this to be mutable
+   |
+LL |     let mut foo = Foo::default();
+   |         +++
+
+error[E0505]: cannot move out of `foo` because it is borrowed
+  --> $DIR/borrow-unpin.rs:43:14
+   |
+LL |     let foo = Foo::default();
+   |         --- binding `foo` declared here
+LL |     let x = &pin mut foo;
+   |             ------------ borrow of `foo` occurs here
+LL |     foo_move(foo);
+   |              ^^^ move out of `foo` occurs here
+LL |
+LL |     foo_pin_mut(x); //
+   |                 - borrow later used here
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:20:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo;
+   |                      --- you could clone this value
+
+error[E0505]: cannot move out of `foo` because it is borrowed
+  --> $DIR/borrow-unpin.rs:56:14
+   |
+LL |     let mut foo = Foo::default();
+   |         ------- binding `foo` declared here
+LL |     let x = &pin mut foo; // ok
+   |             ------------ borrow of `foo` occurs here
+LL |     foo_move(foo);
+   |              ^^^ move out of `foo` occurs here
+LL |
+LL |     foo_pin_mut(x); //
+   |                 - borrow later used here
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:20:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin mut foo; // ok
+   |                      --- you could clone this value
+
+error[E0505]: cannot move out of `foo` because it is borrowed
+  --> $DIR/borrow-unpin.rs:68:14
+   |
+LL |     let foo = Foo::default();
+   |         --- binding `foo` declared here
+LL |     let x = &pin const foo; // ok
+   |             -------------- borrow of `foo` occurs here
+LL |     foo_move(foo);
+   |              ^^^ move out of `foo` occurs here
+LL |
+LL |     foo_pin_ref(x);
+   |                 - borrow later used here
+   |
+note: if `Foo` implemented `Clone`, you could clone the value
+  --> $DIR/borrow-unpin.rs:20:1
+   |
+LL | struct Foo;
+   | ^^^^^^^^^^ consider implementing `Clone` for this type
+...
+LL |     let x = &pin const foo; // ok
+   |                        --- you could clone this value
+
+error[E0502]: cannot borrow `foo` as immutable because it is also borrowed as mutable
+  --> $DIR/borrow-unpin.rs:80:13
+   |
+LL |     let x = &pin mut foo; // ok
+   |             ------------ mutable borrow occurs here
+LL |     foo_ref(&foo);
+   |             ^^^^ immutable borrow occurs here
+LL |
+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-unpin.rs:103:17
+   |
+LL |     let x = &pin mut foo; // ok
+   |             ------------ first mutable borrow occurs here
+LL |     foo_pin_mut(&pin 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-unpin.rs:115:17
+   |
+LL |     let x = &pin const foo; // ok
+   |             -------------- immutable borrow occurs here
+LL |     foo_pin_mut(&pin 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-unpin.rs:127:17
+   |
+LL |     let x = &pin mut foo; // ok
+   |             ------------ mutable borrow occurs here
+LL |     foo_pin_ref(&pin const foo);
+   |                 ^^^^^^^^^^^^^^ immutable borrow occurs here
+LL |
+LL |     foo_pin_mut(x);
+   |                 - mutable borrow later used here
+
+error: aborting due to 9 previous errors
+
+Some errors have detailed explanations: E0499, E0502, E0505, E0596.
+For more information about an error, try `rustc --explain E0499`.
diff --git a/tests/ui/pin-ergonomics/borrow.rs b/tests/ui/pin-ergonomics/borrow.rs
index e33f3c1fa26..f221165848b 100644
--- a/tests/ui/pin-ergonomics/borrow.rs
+++ b/tests/ui/pin-ergonomics/borrow.rs
@@ -1,10 +1,9 @@
 //@ 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)`.
+// `std::pin::pin!(place)` and `Pin::new(&place)`.
 
 use std::pin::Pin;
 
@@ -28,4 +27,12 @@ fn bar() {
     foo_pin_ref(x);
 }
 
+fn baz(mut x: Foo, y: Foo) {
+    let _x = &pin mut x;
+    let _x = x; // ok because `Foo: Unpin` and thus `&pin mut x` doesn't move `x`
+
+    let _y = &pin const y;
+    let _y = y; // ok because `&pin const y` dosn't move `y`
+}
+
 fn main() {}