diff --git a/compiler/rustc_mir_transform/src/gvn.rs b/compiler/rustc_mir_transform/src/gvn.rs
index 981dedd5b5c7..0a54c780f31e 100644
--- a/compiler/rustc_mir_transform/src/gvn.rs
+++ b/compiler/rustc_mir_transform/src/gvn.rs
@@ -872,8 +872,14 @@ impl<'body, 'tcx> VnState<'body, 'tcx> {
                 self.simplify_place_projection(place, location);
                 return self.new_pointer(*place, AddressKind::Address(mutbl));
             }
-            Rvalue::WrapUnsafeBinder(ref mut op, _) => {
-                return self.simplify_operand(op, location);
+            Rvalue::WrapUnsafeBinder(ref mut op, ty) => {
+                let value = self.simplify_operand(op, location)?;
+                Value::Cast {
+                    kind: CastKind::Transmute,
+                    value,
+                    from: op.ty(self.local_decls, self.tcx),
+                    to: ty,
+                }
             }
 
             // Operations.
diff --git a/tests/mir-opt/gvn_on_unsafe_binder.propagate.GVN.diff b/tests/mir-opt/gvn_on_unsafe_binder.propagate.GVN.diff
new file mode 100644
index 000000000000..e28d04f1d588
--- /dev/null
+++ b/tests/mir-opt/gvn_on_unsafe_binder.propagate.GVN.diff
@@ -0,0 +1,35 @@
+- // MIR for `propagate` before GVN
++ // MIR for `propagate` after GVN
+  
+  fn propagate() -> unsafe<> i32 {
+      let mut _0: unsafe<> i32;
+      let _1: i32;
+      let mut _3: i32;
+      scope 1 {
+          debug x => _1;
+          let _2: unsafe<> i32;
+          scope 2 {
+              debug binder => _2;
+          }
+      }
+  
+      bb0: {
+-         StorageLive(_1);
++         nop;
+          _1 = const 1_i32;
+          StorageLive(_2);
+          StorageLive(_3);
+-         _3 = copy _1;
+-         _2 = wrap_binder!(move _3; unsafe<> i32);
++         _3 = const 1_i32;
++         _2 = const {transmute(0x00000001): unsafe<> i32};
+          StorageDead(_3);
+-         _0 = move _2;
++         _0 = const {transmute(0x00000001): unsafe<> i32};
+          StorageDead(_2);
+-         StorageDead(_1);
++         nop;
+          return;
+      }
+  }
+  
diff --git a/tests/mir-opt/gvn_on_unsafe_binder.rs b/tests/mir-opt/gvn_on_unsafe_binder.rs
new file mode 100644
index 000000000000..b3c0576f9906
--- /dev/null
+++ b/tests/mir-opt/gvn_on_unsafe_binder.rs
@@ -0,0 +1,29 @@
+// skip-filecheck
+//@ test-mir-pass: GVN
+
+// EMIT_MIR gvn_on_unsafe_binder.test.GVN.diff
+// EMIT_MIR gvn_on_unsafe_binder.propagate.GVN.diff
+
+#![feature(unsafe_binders)]
+
+use std::unsafe_binder::wrap_binder;
+
+// Test for ICE <https://github.com/rust-lang/rust/issues/137846>.
+fn test() {
+    unsafe {
+        let x = 1;
+        let binder: unsafe<'a> &'a i32 = wrap_binder!(&x);
+    }
+}
+
+// Test that GVN propagates const values through unsafe binders.
+//
+// The lifetime `'a` is redundant (and doesn't print when we print out the type).
+// However, we need it so that rustfmt doesn't rip out the `unsafe<>` part for now.
+fn propagate() -> unsafe<'a> i32 {
+    unsafe {
+        let x = 1;
+        let binder: unsafe<'a> i32 = wrap_binder!(x);
+        binder
+    }
+}
diff --git a/tests/mir-opt/gvn_on_unsafe_binder.test.GVN.diff b/tests/mir-opt/gvn_on_unsafe_binder.test.GVN.diff
new file mode 100644
index 000000000000..33814fb34f3d
--- /dev/null
+++ b/tests/mir-opt/gvn_on_unsafe_binder.test.GVN.diff
@@ -0,0 +1,30 @@
+- // MIR for `test` before GVN
++ // MIR for `test` after GVN
+  
+  fn test() -> () {
+      let mut _0: ();
+      let _1: i32;
+      let mut _3: &i32;
+      scope 1 {
+          debug x => _1;
+          let _2: unsafe<'a> &'a i32;
+          scope 2 {
+              debug binder => _2;
+          }
+      }
+  
+      bb0: {
+          StorageLive(_1);
+          _1 = const 1_i32;
+          StorageLive(_2);
+          StorageLive(_3);
+          _3 = &_1;
+          _2 = wrap_binder!(move _3; unsafe<'a> &'a i32);
+          StorageDead(_3);
+          _0 = const ();
+          StorageDead(_2);
+          StorageDead(_1);
+          return;
+      }
+  }
+