about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2018-10-27 19:29:35 +0000
committerbors <bors@rust-lang.org>2018-10-27 19:29:35 +0000
commitcae6efc37d70ab7d353e6ab9ce229d59a65ed643 (patch)
tree755deb56e86b2436a04ccbab70b3506608e36075
parentb3b87609713887a27ebd07557af14e4aa57771f3 (diff)
parent2f7ea4a8725d433db4f34fca87eb7f61afb7ef9a (diff)
downloadrust-cae6efc37d70ab7d353e6ab9ce229d59a65ed643.tar.gz
rust-cae6efc37d70ab7d353e6ab9ce229d59a65ed643.zip
Auto merge of #54183 - qnighy:by-value-object-safety, r=oli-obk
Implement by-value object safety

This PR implements **by-value object safety**, which is part of unsized rvalues #48055. That means, with `#![feature(unsized_locals)]`, you can call a method `fn foo(self, ...)` on trait objects. One aim of this is to enable `Box<FnOnce>`  in the near future.

The difficulty here is this: when constructing a vtable for a trait `Foo`, we can't just put the function `<T as Foo>::foo` into the table. If `T` is no larger than `usize`, `self` is usually passed directly. However, as the caller of the vtable doesn't know the concrete `Self` type, we want a variant of `<T as Foo>::foo` where `self` is always passed by reference.

Therefore, when the compiler encounters such a method to be generated as a vtable entry, it produces a newly introduced instance called `InstanceDef::VtableShim(def_id)` (that wraps the original instance). the shim just derefs the receiver and calls the original method. We give different symbol names for the shims by appending `::{{vtable-shim}}` to the symbol path (and also adding vtable-shimness as an ingredient to the symbol hash).

r? @eddyb
-rw-r--r--src/doc/unstable-book/src/language-features/unsized-locals.md6
-rw-r--r--src/librustc/ich/impls_ty.rs3
-rw-r--r--src/librustc/ty/instance.rs97
-rw-r--r--src/librustc/ty/mod.rs1
-rw-r--r--src/librustc/ty/structural_impls.rs5
-rw-r--r--src/librustc_codegen_llvm/abi.rs21
-rw-r--r--src/librustc_codegen_llvm/base.rs5
-rw-r--r--src/librustc_codegen_llvm/callee.rs24
-rw-r--r--src/librustc_codegen_llvm/common.rs51
-rw-r--r--src/librustc_codegen_llvm/context.rs6
-rw-r--r--src/librustc_codegen_llvm/declare.rs16
-rw-r--r--src/librustc_codegen_llvm/intrinsic.rs6
-rw-r--r--src/librustc_codegen_llvm/meth.rs2
-rw-r--r--src/librustc_codegen_llvm/mir/block.rs11
-rw-r--r--src/librustc_codegen_llvm/mono_item.rs6
-rw-r--r--src/librustc_codegen_utils/symbol_names.rs13
-rw-r--r--src/librustc_mir/interpret/terminator.rs1
-rw-r--r--src/librustc_mir/monomorphize/collector.rs4
-rw-r--r--src/librustc_mir/monomorphize/partitioning.rs3
-rw-r--r--src/librustc_mir/shim.rs18
-rw-r--r--src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs55
-rw-r--r--src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs69
-rw-r--r--src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs49
-rw-r--r--src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs10
-rw-r--r--src/test/run-pass/unsized-locals/autoderef.rs47
-rw-r--r--src/test/run-pass/unsized-locals/by-value-trait-object-safety-withdefault.rs21
-rw-r--r--src/test/run-pass/unsized-locals/by-value-trait-object-safety.rs23
-rw-r--r--src/test/run-pass/unsized-locals/reference-unsized-locals.rs10
-rw-r--r--src/test/run-pass/unsized-locals/simple-unsized-locals.rs10
-rw-r--r--src/test/run-pass/unsized-locals/unsized-exprs.rs10
-rw-r--r--src/test/run-pass/unsized-locals/unsized-parameters.rs10
-rw-r--r--src/test/ui/symbol-names/basic.stderr2
-rw-r--r--src/test/ui/symbol-names/impl1.stderr4
-rw-r--r--src/test/ui/unsized-locals/borrow-after-move.nll.stderr51
-rw-r--r--src/test/ui/unsized-locals/borrow-after-move.rs42
-rw-r--r--src/test/ui/unsized-locals/borrow-after-move.stderr57
-rw-r--r--src/test/ui/unsized-locals/by-value-trait-object-safety.rs20
-rw-r--r--src/test/ui/unsized-locals/by-value-trait-object-safety.stderr8
-rw-r--r--src/test/ui/unsized-locals/double-move.nll.stderr55
-rw-r--r--src/test/ui/unsized-locals/double-move.rs53
-rw-r--r--src/test/ui/unsized-locals/double-move.stderr63
-rw-r--r--src/test/ui/unsized-locals/unsized-exprs.rs (renamed from src/test/compile-fail/unsized-locals/unsized-exprs.rs)10
-rw-r--r--src/test/ui/unsized-locals/unsized-exprs.stderr25
-rw-r--r--src/test/ui/unsized-locals/unsized-exprs2.nll.stderr19
-rw-r--r--src/test/ui/unsized-locals/unsized-exprs2.rs (renamed from src/test/compile-fail/unsized-locals/unsized-exprs2.rs)10
-rw-r--r--src/test/ui/unsized-locals/unsized-exprs2.stderr9
46 files changed, 870 insertions, 171 deletions
diff --git a/src/doc/unstable-book/src/language-features/unsized-locals.md b/src/doc/unstable-book/src/language-features/unsized-locals.md
index 7a5fe5b7f28..6f7cf754ae0 100644
--- a/src/doc/unstable-book/src/language-features/unsized-locals.md
+++ b/src/doc/unstable-book/src/language-features/unsized-locals.md
@@ -101,9 +101,9 @@ fn main() {
 }
 ```
 
-And `Foo` will also be object-safe. However, this object-safety is not yet implemented.
+And `Foo` will also be object-safe.
 
-```rust,ignore
+```rust
 #![feature(unsized_locals)]
 
 trait Foo {
@@ -119,8 +119,6 @@ fn main () {
 }
 ```
 
-Unfortunately, this is not implemented yet.
-
 One of the objectives of this feature is to allow `Box<dyn FnOnce>`, instead of `Box<dyn FnBox>` in the future. See [#28796] for details.
 
 [#28796]: https://github.com/rust-lang/rust/issues/28796
diff --git a/src/librustc/ich/impls_ty.rs b/src/librustc/ich/impls_ty.rs
index 7e5d19850f4..0c38cb10a23 100644
--- a/src/librustc/ich/impls_ty.rs
+++ b/src/librustc/ich/impls_ty.rs
@@ -1007,6 +1007,9 @@ impl<'a, 'gcx> HashStable<StableHashingContext<'a>> for ty::InstanceDef<'gcx> {
             ty::InstanceDef::Item(def_id) => {
                 def_id.hash_stable(hcx, hasher);
             }
+            ty::InstanceDef::VtableShim(def_id) => {
+                def_id.hash_stable(hcx, hasher);
+            }
             ty::InstanceDef::Intrinsic(def_id) => {
                 def_id.hash_stable(hcx, hasher);
             }
diff --git a/src/librustc/ty/instance.rs b/src/librustc/ty/instance.rs
index 3d205215d64..041565c8b5a 100644
--- a/src/librustc/ty/instance.rs
+++ b/src/librustc/ty/instance.rs
@@ -8,13 +8,15 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+use hir::Unsafety;
 use hir::def_id::DefId;
-use ty::{self, Ty, TypeFoldable, Substs, TyCtxt};
+use ty::{self, Ty, PolyFnSig, TypeFoldable, Substs, TyCtxt};
 use traits;
 use rustc_target::spec::abi::Abi;
 use util::ppaux;
 
 use std::fmt;
+use std::iter;
 
 #[derive(Copy, Clone, PartialEq, Eq, Hash, Debug, RustcEncodable, RustcDecodable)]
 pub struct Instance<'tcx> {
@@ -27,6 +29,9 @@ pub enum InstanceDef<'tcx> {
     Item(DefId),
     Intrinsic(DefId),
 
+    /// `<T as Trait>::method` where `method` receives unsizeable `self: Self`.
+    VtableShim(DefId),
+
     /// \<fn() as FnTrait>::call_*
     /// def-id is FnTrait::call_*
     FnPtrShim(DefId, Ty<'tcx>),
@@ -56,6 +61,65 @@ impl<'a, 'tcx> Instance<'tcx> {
             &ty,
         )
     }
+
+    fn fn_sig_noadjust(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> PolyFnSig<'tcx> {
+        let ty = self.ty(tcx);
+        match ty.sty {
+            ty::FnDef(..) |
+            // Shims currently have type FnPtr. Not sure this should remain.
+            ty::FnPtr(_) => ty.fn_sig(tcx),
+            ty::Closure(def_id, substs) => {
+                let sig = substs.closure_sig(def_id, tcx);
+
+                let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
+                sig.map_bound(|sig| tcx.mk_fn_sig(
+                    iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
+                    sig.output(),
+                    sig.variadic,
+                    sig.unsafety,
+                    sig.abi
+                ))
+            }
+            ty::Generator(def_id, substs, _) => {
+                let sig = substs.poly_sig(def_id, tcx);
+
+                let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
+                let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
+
+                sig.map_bound(|sig| {
+                    let state_did = tcx.lang_items().gen_state().unwrap();
+                    let state_adt_ref = tcx.adt_def(state_did);
+                    let state_substs = tcx.intern_substs(&[
+                        sig.yield_ty.into(),
+                        sig.return_ty.into(),
+                    ]);
+                    let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
+
+                    tcx.mk_fn_sig(iter::once(env_ty),
+                        ret_ty,
+                        false,
+                        Unsafety::Normal,
+                        Abi::Rust
+                    )
+                })
+            }
+            _ => bug!("unexpected type {:?} in Instance::fn_sig_noadjust", ty)
+        }
+    }
+
+    pub fn fn_sig(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>) -> ty::PolyFnSig<'tcx> {
+        let mut fn_sig = self.fn_sig_noadjust(tcx);
+        if let InstanceDef::VtableShim(..) = self.def {
+            // Modify fn(self, ...) to fn(self: *mut Self, ...)
+            fn_sig = fn_sig.map_bound(|mut fn_sig| {
+                let mut inputs_and_output = fn_sig.inputs_and_output.to_vec();
+                inputs_and_output[0] = tcx.mk_mut_ptr(inputs_and_output[0]);
+                fn_sig.inputs_and_output = tcx.intern_type_list(&inputs_and_output);
+                fn_sig
+            });
+        }
+        fn_sig
+    }
 }
 
 impl<'tcx> InstanceDef<'tcx> {
@@ -63,6 +127,7 @@ impl<'tcx> InstanceDef<'tcx> {
     pub fn def_id(&self) -> DefId {
         match *self {
             InstanceDef::Item(def_id) |
+            InstanceDef::VtableShim(def_id) |
             InstanceDef::FnPtrShim(def_id, _) |
             InstanceDef::Virtual(def_id, _) |
             InstanceDef::Intrinsic(def_id, ) |
@@ -120,6 +185,9 @@ impl<'tcx> fmt::Display for Instance<'tcx> {
         ppaux::parameterized(f, self.substs, self.def_id(), &[])?;
         match self.def {
             InstanceDef::Item(_) => Ok(()),
+            InstanceDef::VtableShim(_) => {
+                write!(f, " - shim(vtable)")
+            }
             InstanceDef::Intrinsic(_) => {
                 write!(f, " - intrinsic")
             }
@@ -230,6 +298,25 @@ impl<'a, 'b, 'tcx> Instance<'tcx> {
         result
     }
 
+    pub fn resolve_for_vtable(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                              param_env: ty::ParamEnv<'tcx>,
+                              def_id: DefId,
+                              substs: &'tcx Substs<'tcx>) -> Option<Instance<'tcx>> {
+        debug!("resolve(def_id={:?}, substs={:?})", def_id, substs);
+        let fn_sig = tcx.fn_sig(def_id);
+        let is_vtable_shim =
+            fn_sig.inputs().skip_binder().len() > 0 && fn_sig.input(0).skip_binder().is_self();
+        if is_vtable_shim {
+            debug!(" => associated item with unsizeable self: Self");
+            Some(Instance {
+                def: InstanceDef::VtableShim(def_id),
+                substs,
+            })
+        } else {
+            Instance::resolve(tcx, param_env, def_id, substs)
+        }
+    }
+
     pub fn resolve_closure(
         tcx: TyCtxt<'a, 'tcx, 'tcx>,
         def_id: DefId,
@@ -244,6 +331,14 @@ impl<'a, 'b, 'tcx> Instance<'tcx> {
             _ => Instance::new(def_id, substs.substs)
         }
     }
+
+    pub fn is_vtable_shim(&self) -> bool {
+        if let InstanceDef::VtableShim(..) = self.def {
+            true
+        } else {
+            false
+        }
+    }
 }
 
 fn resolve_associated_item<'a, 'tcx>(
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index 48ba69fee1c..f8fc2cc8303 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -2761,6 +2761,7 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
             ty::InstanceDef::Item(did) => {
                 self.optimized_mir(did)
             }
+            ty::InstanceDef::VtableShim(..) |
             ty::InstanceDef::Intrinsic(..) |
             ty::InstanceDef::FnPtrShim(..) |
             ty::InstanceDef::Virtual(..) |
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 62827ea20c3..ba5b714a0e7 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -467,6 +467,8 @@ impl<'a, 'tcx> Lift<'tcx> for ty::InstanceDef<'a> {
         match *self {
             ty::InstanceDef::Item(def_id) =>
                 Some(ty::InstanceDef::Item(def_id)),
+            ty::InstanceDef::VtableShim(def_id) =>
+                Some(ty::InstanceDef::VtableShim(def_id)),
             ty::InstanceDef::Intrinsic(def_id) =>
                 Some(ty::InstanceDef::Intrinsic(def_id)),
             ty::InstanceDef::FnPtrShim(def_id, ref ty) =>
@@ -647,6 +649,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
             substs: self.substs.fold_with(folder),
             def: match self.def {
                 Item(did) => Item(did.fold_with(folder)),
+                VtableShim(did) => VtableShim(did.fold_with(folder)),
                 Intrinsic(did) => Intrinsic(did.fold_with(folder)),
                 FnPtrShim(did, ty) => FnPtrShim(
                     did.fold_with(folder),
@@ -675,7 +678,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::instance::Instance<'tcx> {
         use ty::InstanceDef::*;
         self.substs.visit_with(visitor) ||
         match self.def {
-            Item(did) | Intrinsic(did) | Virtual(did, _) => {
+            Item(did) | VtableShim(did) | Intrinsic(did) | Virtual(did, _) => {
                 did.visit_with(visitor)
             },
             FnPtrShim(did, ty) | CloneShim(did, ty) => {
diff --git a/src/librustc_codegen_llvm/abi.rs b/src/librustc_codegen_llvm/abi.rs
index 7b93d3e795e..7c7662a88de 100644
--- a/src/librustc_codegen_llvm/abi.rs
+++ b/src/librustc_codegen_llvm/abi.rs
@@ -11,7 +11,7 @@
 use llvm::{self, AttributePlace};
 use base;
 use builder::{Builder, MemFlags};
-use common::{ty_fn_sig, C_usize};
+use common::C_usize;
 use context::CodegenCx;
 use mir::place::PlaceRef;
 use mir::operand::OperandValue;
@@ -283,8 +283,7 @@ pub trait FnTypeExt<'tcx> {
 
 impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
     fn of_instance(cx: &CodegenCx<'ll, 'tcx>, instance: &ty::Instance<'tcx>) -> Self {
-        let fn_ty = instance.ty(cx.tcx);
-        let sig = ty_fn_sig(cx, fn_ty);
+        let sig = instance.fn_sig(cx.tcx);
         let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
         FnType::new(cx, sig, &[])
     }
@@ -305,17 +304,17 @@ impl<'tcx> FnTypeExt<'tcx> for FnType<'tcx, Ty<'tcx>> {
             // Don't pass the vtable, it's not an argument of the virtual fn.
             // Instead, pass just the (thin pointer) first field of `*dyn Trait`.
             if arg_idx == Some(0) {
-                if layout.is_unsized() {
-                    unimplemented!("by-value trait object is not \
-                                    yet implemented in #![feature(unsized_locals)]");
-                }
                 // FIXME(eddyb) `layout.field(cx, 0)` is not enough because e.g.
                 // `Box<dyn Trait>` has a few newtype wrappers around the raw
                 // pointer, so we'd have to "dig down" to find `*dyn Trait`.
-                let pointee = layout.ty.builtin_deref(true)
-                    .unwrap_or_else(|| {
-                        bug!("FnType::new_vtable: non-pointer self {:?}", layout)
-                    }).ty;
+                let pointee = if layout.is_unsized() {
+                    layout.ty
+                } else {
+                    layout.ty.builtin_deref(true)
+                        .unwrap_or_else(|| {
+                            bug!("FnType::new_vtable: non-pointer self {:?}", layout)
+                        }).ty
+                };
                 let fat_ptr_ty = cx.tcx.mk_mut_ptr(pointee);
                 layout = cx.layout_of(fat_ptr_ty).field(cx, 0);
             }
diff --git a/src/librustc_codegen_llvm/base.rs b/src/librustc_codegen_llvm/base.rs
index a9119d49e8b..a4c7a7123b9 100644
--- a/src/librustc_codegen_llvm/base.rs
+++ b/src/librustc_codegen_llvm/base.rs
@@ -56,7 +56,7 @@ use callee;
 use common::{C_bool, C_bytes_in_context, C_i32, C_usize};
 use rustc_mir::monomorphize::collector::{self, MonoItemCollectionMode};
 use rustc_mir::monomorphize::item::DefPathBasedNames;
-use common::{self, C_struct_in_context, C_array, val_ty};
+use common::{C_struct_in_context, C_array, val_ty};
 use consts;
 use context::CodegenCx;
 use debuginfo;
@@ -491,8 +491,7 @@ pub fn codegen_instance<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>, instance: Instance<'
     // release builds.
     info!("codegen_instance({})", instance);
 
-    let fn_ty = instance.ty(cx.tcx);
-    let sig = common::ty_fn_sig(cx, fn_ty);
+    let sig = instance.fn_sig(cx.tcx);
     let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
 
     let lldecl = cx.instances.borrow().get(&instance).cloned().unwrap_or_else(||
diff --git a/src/librustc_codegen_llvm/callee.rs b/src/librustc_codegen_llvm/callee.rs
index 4b4ccb3b600..7300bac9618 100644
--- a/src/librustc_codegen_llvm/callee.rs
+++ b/src/librustc_codegen_llvm/callee.rs
@@ -47,16 +47,16 @@ pub fn get_fn(
     assert!(!instance.substs.has_escaping_regions());
     assert!(!instance.substs.has_param_types());
 
-    let fn_ty = instance.ty(cx.tcx);
+    let sig = instance.fn_sig(cx.tcx);
     if let Some(&llfn) = cx.instances.borrow().get(&instance) {
         return llfn;
     }
 
     let sym = tcx.symbol_name(instance).as_str();
-    debug!("get_fn({:?}: {:?}) => {}", instance, fn_ty, sym);
+    debug!("get_fn({:?}: {:?}) => {}", instance, sig, sym);
 
     // Create a fn pointer with the substituted signature.
-    let fn_ptr_ty = tcx.mk_fn_ptr(common::ty_fn_sig(cx, fn_ty));
+    let fn_ptr_ty = tcx.mk_fn_ptr(sig);
     let llptrty = cx.layout_of(fn_ptr_ty).llvm_type(cx);
 
     let llfn = if let Some(llfn) = declare::get_declared_value(cx, &sym) {
@@ -91,7 +91,7 @@ pub fn get_fn(
             llfn
         }
     } else {
-        let llfn = declare::declare_fn(cx, &sym, fn_ty);
+        let llfn = declare::declare_fn(cx, &sym, sig);
         assert_eq!(common::val_ty(llfn), llptrty);
         debug!("get_fn: not casting pointer!");
 
@@ -220,3 +220,19 @@ pub fn resolve_and_get_fn(
         ).unwrap()
     )
 }
+
+pub fn resolve_and_get_fn_for_vtable(
+    cx: &CodegenCx<'ll, 'tcx>,
+    def_id: DefId,
+    substs: &'tcx Substs<'tcx>,
+) -> &'ll Value {
+    get_fn(
+        cx,
+        ty::Instance::resolve_for_vtable(
+            cx.tcx,
+            ty::ParamEnv::reveal_all(),
+            def_id,
+            substs
+        ).unwrap()
+    )
+}
diff --git a/src/librustc_codegen_llvm/common.rs b/src/librustc_codegen_llvm/common.rs
index c08937fa9b9..c9b464fd8f3 100644
--- a/src/librustc_codegen_llvm/common.rs
+++ b/src/librustc_codegen_llvm/common.rs
@@ -30,9 +30,7 @@ use rustc::ty::layout::{HasDataLayout, LayoutOf};
 use rustc::hir;
 
 use libc::{c_uint, c_char};
-use std::iter;
 
-use rustc_target::spec::abi::Abi;
 use syntax::symbol::LocalInternedString;
 use syntax_pos::{Span, DUMMY_SP};
 
@@ -404,52 +402,3 @@ pub fn shift_mask_val(
         _ => bug!("shift_mask_val: expected Integer or Vector, found {:?}", kind),
     }
 }
-
-pub fn ty_fn_sig<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
-                           ty: Ty<'tcx>)
-                           -> ty::PolyFnSig<'tcx>
-{
-    match ty.sty {
-        ty::FnDef(..) |
-        // Shims currently have type FnPtr. Not sure this should remain.
-        ty::FnPtr(_) => ty.fn_sig(cx.tcx),
-        ty::Closure(def_id, substs) => {
-            let tcx = cx.tcx;
-            let sig = substs.closure_sig(def_id, tcx);
-
-            let env_ty = tcx.closure_env_ty(def_id, substs).unwrap();
-            sig.map_bound(|sig| tcx.mk_fn_sig(
-                iter::once(*env_ty.skip_binder()).chain(sig.inputs().iter().cloned()),
-                sig.output(),
-                sig.variadic,
-                sig.unsafety,
-                sig.abi
-            ))
-        }
-        ty::Generator(def_id, substs, _) => {
-            let tcx = cx.tcx;
-            let sig = substs.poly_sig(def_id, cx.tcx);
-
-            let env_region = ty::ReLateBound(ty::INNERMOST, ty::BrEnv);
-            let env_ty = tcx.mk_mut_ref(tcx.mk_region(env_region), ty);
-
-            sig.map_bound(|sig| {
-                let state_did = tcx.lang_items().gen_state().unwrap();
-                let state_adt_ref = tcx.adt_def(state_did);
-                let state_substs = tcx.intern_substs(&[
-                    sig.yield_ty.into(),
-                    sig.return_ty.into(),
-                ]);
-                let ret_ty = tcx.mk_adt(state_adt_ref, state_substs);
-
-                tcx.mk_fn_sig(iter::once(env_ty),
-                    ret_ty,
-                    false,
-                    hir::Unsafety::Normal,
-                    Abi::Rust
-                )
-            })
-        }
-        _ => bug!("unexpected type {:?} to ty_fn_sig", ty)
-    }
-}
diff --git a/src/librustc_codegen_llvm/context.rs b/src/librustc_codegen_llvm/context.rs
index 826df82193a..241f7989e16 100644
--- a/src/librustc_codegen_llvm/context.rs
+++ b/src/librustc_codegen_llvm/context.rs
@@ -404,15 +404,15 @@ impl<'b, 'tcx> CodegenCx<'b, 'tcx> {
             return llfn;
         }
 
-        let ty = tcx.mk_fn_ptr(ty::Binder::bind(tcx.mk_fn_sig(
+        let sig = ty::Binder::bind(tcx.mk_fn_sig(
             iter::once(tcx.mk_mut_ptr(tcx.types.u8)),
             tcx.types.never,
             false,
             hir::Unsafety::Unsafe,
             Abi::C
-        )));
+        ));
 
-        let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", ty);
+        let llfn = declare::declare_fn(self, "rust_eh_unwind_resume", sig);
         attributes::unwind(llfn, true);
         attributes::apply_target_cpu_attr(self, llfn);
         unwresume.set(Some(llfn));
diff --git a/src/librustc_codegen_llvm/declare.rs b/src/librustc_codegen_llvm/declare.rs
index 26969e24f08..f4aede55ce1 100644
--- a/src/librustc_codegen_llvm/declare.rs
+++ b/src/librustc_codegen_llvm/declare.rs
@@ -22,7 +22,7 @@
 
 use llvm;
 use llvm::AttributePlace::Function;
-use rustc::ty::{self, Ty};
+use rustc::ty::{self, PolyFnSig};
 use rustc::ty::layout::LayoutOf;
 use rustc::session::config::Sanitizer;
 use rustc_data_structures::small_c_str::SmallCStr;
@@ -30,7 +30,6 @@ use rustc_target::spec::PanicStrategy;
 use abi::{Abi, FnType, FnTypeExt};
 use attributes;
 use context::CodegenCx;
-use common;
 use type_::Type;
 use value::Value;
 
@@ -129,10 +128,9 @@ pub fn declare_cfn(cx: &CodegenCx<'ll, '_>, name: &str, fn_type: &'ll Type) -> &
 pub fn declare_fn(
     cx: &CodegenCx<'ll, 'tcx>,
     name: &str,
-    fn_type: Ty<'tcx>,
+    sig: PolyFnSig<'tcx>,
 ) -> &'ll Value {
-    debug!("declare_rust_fn(name={:?}, fn_type={:?})", name, fn_type);
-    let sig = common::ty_fn_sig(cx, fn_type);
+    debug!("declare_rust_fn(name={:?}, sig={:?})", name, sig);
     let sig = cx.tcx.normalize_erasing_late_bound_regions(ty::ParamEnv::reveal_all(), &sig);
     debug!("declare_rust_fn (after region erasure) sig={:?}", sig);
 
@@ -184,12 +182,12 @@ pub fn define_private_global(cx: &CodegenCx<'ll, '_>, ty: &'ll Type) -> &'ll Val
 pub fn define_fn(
     cx: &CodegenCx<'ll, 'tcx>,
     name: &str,
-    fn_type: Ty<'tcx>,
+    fn_sig: PolyFnSig<'tcx>,
 ) -> &'ll Value {
     if get_defined_value(cx, name).is_some() {
         cx.sess().fatal(&format!("symbol `{}` already defined", name))
     } else {
-        declare_fn(cx, name, fn_type)
+        declare_fn(cx, name, fn_sig)
     }
 }
 
@@ -201,9 +199,9 @@ pub fn define_fn(
 pub fn define_internal_fn(
     cx: &CodegenCx<'ll, 'tcx>,
     name: &str,
-    fn_type: Ty<'tcx>,
+    fn_sig: PolyFnSig<'tcx>,
 ) -> &'ll Value {
-    let llfn = define_fn(cx, name, fn_type);
+    let llfn = define_fn(cx, name, fn_sig);
     unsafe { llvm::LLVMRustSetLinkage(llfn, llvm::Linkage::InternalLinkage) };
     llfn
 }
diff --git a/src/librustc_codegen_llvm/intrinsic.rs b/src/librustc_codegen_llvm/intrinsic.rs
index 272196afa6f..03244c18ac3 100644
--- a/src/librustc_codegen_llvm/intrinsic.rs
+++ b/src/librustc_codegen_llvm/intrinsic.rs
@@ -933,14 +933,14 @@ fn gen_fn<'ll, 'tcx>(
     output: Ty<'tcx>,
     codegen: &mut dyn FnMut(Builder<'_, 'll, 'tcx>),
 ) -> &'ll Value {
-    let rust_fn_ty = cx.tcx.mk_fn_ptr(ty::Binder::bind(cx.tcx.mk_fn_sig(
+    let rust_fn_sig = ty::Binder::bind(cx.tcx.mk_fn_sig(
         inputs.into_iter(),
         output,
         false,
         hir::Unsafety::Unsafe,
         Abi::Rust
-    )));
-    let llfn = declare::define_internal_fn(cx, name, rust_fn_ty);
+    ));
+    let llfn = declare::define_internal_fn(cx, name, rust_fn_sig);
     attributes::from_fn_attrs(cx, llfn, None);
     let bx = Builder::new_block(cx, llfn, "entry-block");
     codegen(bx);
diff --git a/src/librustc_codegen_llvm/meth.rs b/src/librustc_codegen_llvm/meth.rs
index 29c2e71960c..d38f343d01f 100644
--- a/src/librustc_codegen_llvm/meth.rs
+++ b/src/librustc_codegen_llvm/meth.rs
@@ -89,7 +89,7 @@ pub fn get_vtable(
     let methods = tcx.vtable_methods(trait_ref.with_self_ty(tcx, ty));
     let methods = methods.iter().cloned().map(|opt_mth| {
         opt_mth.map_or(nullptr, |(def_id, substs)| {
-            callee::resolve_and_get_fn(cx, def_id, substs)
+            callee::resolve_and_get_fn_for_vtable(cx, def_id, substs)
         })
     });
 
diff --git a/src/librustc_codegen_llvm/mir/block.rs b/src/librustc_codegen_llvm/mir/block.rs
index 68e30227185..d98b7869ae9 100644
--- a/src/librustc_codegen_llvm/mir/block.rs
+++ b/src/librustc_codegen_llvm/mir/block.rs
@@ -298,8 +298,7 @@ impl FunctionCx<'a, 'll, 'tcx> {
                 };
                 let (drop_fn, fn_ty) = match ty.sty {
                     ty::Dynamic(..) => {
-                        let fn_ty = drop_fn.ty(bx.cx.tcx);
-                        let sig = common::ty_fn_sig(bx.cx, fn_ty);
+                        let sig = drop_fn.fn_sig(bx.cx.tcx);
                         let sig = bx.tcx().normalize_erasing_late_bound_regions(
                             ty::ParamEnv::reveal_all(),
                             &sig,
@@ -651,6 +650,14 @@ impl FunctionCx<'a, 'll, 'tcx> {
                                 .get_fn(&bx, meta, &fn_ty));
                             llargs.push(data_ptr);
                             continue;
+                        } else if let Ref(data_ptr, Some(meta), _) = op.val {
+                            // by-value dynamic dispatch
+                            llfn = Some(meth::VirtualIndex::from_index(idx)
+                                .get_fn(&bx, meta, &fn_ty));
+                            llargs.push(data_ptr);
+                            continue;
+                        } else {
+                            span_bug!(span, "can't codegen a virtual call on {:?}", op);
                         }
                     }
 
diff --git a/src/librustc_codegen_llvm/mono_item.rs b/src/librustc_codegen_llvm/mono_item.rs
index dab9b147cc0..91c1ccbe002 100644
--- a/src/librustc_codegen_llvm/mono_item.rs
+++ b/src/librustc_codegen_llvm/mono_item.rs
@@ -153,9 +153,9 @@ fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
     assert!(!instance.substs.needs_infer() &&
             !instance.substs.has_param_types());
 
-    let mono_ty = instance.ty(cx.tcx);
+    let mono_sig = instance.fn_sig(cx.tcx);
     let attrs = cx.tcx.codegen_fn_attrs(instance.def_id());
-    let lldecl = declare::declare_fn(cx, symbol_name, mono_ty);
+    let lldecl = declare::declare_fn(cx, symbol_name, mono_sig);
     unsafe { llvm::LLVMRustSetLinkage(lldecl, base::linkage_to_llvm(linkage)) };
     base::set_link_section(lldecl, &attrs);
     if linkage == Linkage::LinkOnceODR ||
@@ -178,7 +178,7 @@ fn predefine_fn<'a, 'tcx>(cx: &CodegenCx<'a, 'tcx>,
         }
     }
 
-    debug!("predefine_fn: mono_ty = {:?} instance = {:?}", mono_ty, instance);
+    debug!("predefine_fn: mono_sig = {:?} instance = {:?}", mono_sig, instance);
     if instance.def.is_inline(cx.tcx) {
         attributes::inline(cx, lldecl, attributes::InlineAttr::Hint);
     }
diff --git a/src/librustc_codegen_utils/symbol_names.rs b/src/librustc_codegen_utils/symbol_names.rs
index c1e80234a77..0d95b0c7bbc 100644
--- a/src/librustc_codegen_utils/symbol_names.rs
+++ b/src/librustc_codegen_utils/symbol_names.rs
@@ -114,6 +114,7 @@ use rustc_mir::monomorphize::Instance;
 use syntax_pos::symbol::Symbol;
 
 use std::fmt::Write;
+use std::mem::discriminant;
 
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
@@ -219,6 +220,10 @@ fn get_symbol_hash<'a, 'tcx>(
                 .hash_stable(&mut hcx, &mut hasher);
             (&tcx.crate_disambiguator(instantiating_crate)).hash_stable(&mut hcx, &mut hasher);
         }
+
+        // We want to avoid accidental collision between different types of instances.
+        // Especially, VtableShim may overlap with its original instance without this.
+        discriminant(&instance.def).hash_stable(&mut hcx, &mut hasher);
     });
 
     // 64 bits should be enough to avoid collisions.
@@ -322,7 +327,13 @@ fn compute_symbol_name<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance: Instance
 
     let hash = get_symbol_hash(tcx, def_id, instance, instance_ty, substs);
 
-    SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id)).finish(hash)
+    let mut buf = SymbolPathBuffer::from_interned(tcx.def_symbol_name(def_id));
+
+    if instance.is_vtable_shim() {
+        buf.push("{{vtable-shim}}");
+    }
+
+    buf.finish(hash)
 }
 
 // Follow C++ namespace-mangling style, see
diff --git a/src/librustc_mir/interpret/terminator.rs b/src/librustc_mir/interpret/terminator.rs
index faeeb24c6c2..ee84e49022f 100644
--- a/src/librustc_mir/interpret/terminator.rs
+++ b/src/librustc_mir/interpret/terminator.rs
@@ -256,6 +256,7 @@ impl<'a, 'mir, 'tcx, M: Machine<'a, 'mir, 'tcx>> EvalContext<'a, 'mir, 'tcx, M>
                 self.dump_place(*dest);
                 Ok(())
             }
+            ty::InstanceDef::VtableShim(..) |
             ty::InstanceDef::ClosureOnceShim { .. } |
             ty::InstanceDef::FnPtrShim(..) |
             ty::InstanceDef::DropGlue(..) |
diff --git a/src/librustc_mir/monomorphize/collector.rs b/src/librustc_mir/monomorphize/collector.rs
index e8c482e836f..8c696669132 100644
--- a/src/librustc_mir/monomorphize/collector.rs
+++ b/src/librustc_mir/monomorphize/collector.rs
@@ -705,6 +705,7 @@ fn visit_instance_use<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                 bug!("intrinsic {:?} being reified", def_id);
             }
         }
+        ty::InstanceDef::VtableShim(..) |
         ty::InstanceDef::Virtual(..) |
         ty::InstanceDef::DropGlue(_, None) => {
             // don't need to emit shim if we are calling directly.
@@ -731,6 +732,7 @@ fn should_monomorphize_locally<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, instance:
                                          -> bool {
     let def_id = match instance.def {
         ty::InstanceDef::Item(def_id) => def_id,
+        ty::InstanceDef::VtableShim(..) |
         ty::InstanceDef::ClosureOnceShim { .. } |
         ty::InstanceDef::Virtual(..) |
         ty::InstanceDef::FnPtrShim(..) |
@@ -913,7 +915,7 @@ fn create_mono_items_for_vtable_methods<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         // Walk all methods of the trait, including those of its supertraits
         let methods = tcx.vtable_methods(poly_trait_ref);
         let methods = methods.iter().cloned().filter_map(|method| method)
-            .map(|(def_id, substs)| ty::Instance::resolve(
+            .map(|(def_id, substs)| ty::Instance::resolve_for_vtable(
                     tcx,
                     ty::ParamEnv::reveal_all(),
                     def_id,
diff --git a/src/librustc_mir/monomorphize/partitioning.rs b/src/librustc_mir/monomorphize/partitioning.rs
index 3a1108bb169..f0a35ca7adb 100644
--- a/src/librustc_mir/monomorphize/partitioning.rs
+++ b/src/librustc_mir/monomorphize/partitioning.rs
@@ -180,6 +180,7 @@ pub trait CodegenUnitExt<'tcx> {
                         InstanceDef::Item(def_id) => {
                             tcx.hir.as_local_node_id(def_id)
                         }
+                        InstanceDef::VtableShim(..) |
                         InstanceDef::Intrinsic(..) |
                         InstanceDef::FnPtrShim(..) |
                         InstanceDef::Virtual(..) |
@@ -422,6 +423,7 @@ fn mono_item_visibility(
         InstanceDef::Item(def_id) => def_id,
 
         // These are all compiler glue and such, never exported, always hidden.
+        InstanceDef::VtableShim(..) |
         InstanceDef::FnPtrShim(..) |
         InstanceDef::Virtual(..) |
         InstanceDef::Intrinsic(..) |
@@ -756,6 +758,7 @@ fn characteristic_def_id_of_mono_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
         MonoItem::Fn(instance) => {
             let def_id = match instance.def {
                 ty::InstanceDef::Item(def_id) => def_id,
+                ty::InstanceDef::VtableShim(..) |
                 ty::InstanceDef::FnPtrShim(..) |
                 ty::InstanceDef::ClosureOnceShim { .. } |
                 ty::InstanceDef::Intrinsic(..) |
diff --git a/src/librustc_mir/shim.rs b/src/librustc_mir/shim.rs
index 6c32690cdb3..7061504cd0a 100644
--- a/src/librustc_mir/shim.rs
+++ b/src/librustc_mir/shim.rs
@@ -43,6 +43,15 @@ fn make_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let mut result = match instance {
         ty::InstanceDef::Item(..) =>
             bug!("item {:?} passed to make_shim", instance),
+        ty::InstanceDef::VtableShim(def_id) => {
+            build_call_shim(
+                tcx,
+                def_id,
+                Adjustment::DerefMove,
+                CallKind::Direct(def_id),
+                None,
+            )
+        }
         ty::InstanceDef::FnPtrShim(def_id, ty) => {
             let trait_ = tcx.trait_of_item(def_id).unwrap();
             let adjustment = match tcx.lang_items().fn_trait_kind(trait_) {
@@ -128,6 +137,7 @@ fn make_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 enum Adjustment {
     Identity,
     Deref,
+    DerefMove,
     RefMut,
 }
 
@@ -701,6 +711,14 @@ fn build_call_shim<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     let rcvr = match rcvr_adjustment {
         Adjustment::Identity => Operand::Move(rcvr_l),
         Adjustment::Deref => Operand::Copy(rcvr_l.deref()),
+        Adjustment::DerefMove => {
+            // fn(Self, ...) -> fn(*mut Self, ...)
+            let arg_ty = local_decls[rcvr_arg].ty;
+            assert!(arg_ty.is_self());
+            local_decls[rcvr_arg].ty = tcx.mk_mut_ptr(arg_ty);
+
+            Operand::Move(rcvr_l.deref())
+        }
         Adjustment::RefMut => {
             // let rcvr = &mut rcvr;
             let ref_rcvr = local_decls.push(temp_decl(
diff --git a/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs b/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs
new file mode 100644
index 00000000000..7f365ce2bba
--- /dev/null
+++ b/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call.rs
@@ -0,0 +1,55 @@
+#![feature(unsized_locals)]
+#![feature(unboxed_closures)]
+
+pub trait FnOnce<Args> {
+    type Output;
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+struct A;
+
+impl FnOnce<()> for A {
+    type Output = String;
+    extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
+        format!("hello")
+    }
+}
+
+struct B(i32);
+
+impl FnOnce<()> for B {
+    type Output = String;
+    extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
+        format!("{}", self.0)
+    }
+}
+
+struct C(String);
+
+impl FnOnce<()> for C {
+    type Output = String;
+    extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
+        self.0
+    }
+}
+
+struct D(Box<String>);
+
+impl FnOnce<()> for D {
+    type Output = String;
+    extern "rust-call" fn call_once(self, (): ()) -> Self::Output {
+        *self.0
+    }
+}
+
+
+fn main() {
+    let x = *(Box::new(A) as Box<dyn FnOnce<(), Output = String>>);
+    assert_eq!(x.call_once(()), format!("hello"));
+    let x = *(Box::new(B(42)) as Box<dyn FnOnce<(), Output = String>>);
+    assert_eq!(x.call_once(()), format!("42"));
+    let x = *(Box::new(C(format!("jumping fox"))) as Box<dyn FnOnce<(), Output = String>>);
+    assert_eq!(x.call_once(()), format!("jumping fox"));
+    let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box<dyn FnOnce<(), Output = String>>);
+    assert_eq!(x.call_once(()), format!("lazy dog"));
+}
diff --git a/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs b/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs
new file mode 100644
index 00000000000..a78b897d194
--- /dev/null
+++ b/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects-rust-call2.rs
@@ -0,0 +1,69 @@
+#![feature(unsized_locals)]
+#![feature(unboxed_closures)]
+
+pub trait FnOnce<Args> {
+    type Output;
+    extern "rust-call" fn call_once(self, args: Args) -> Self::Output;
+}
+
+struct A;
+
+impl FnOnce<(String, Box<str>)> for A {
+    type Output = String;
+    extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
+        assert_eq!(&s1 as &str, "s1");
+        assert_eq!(&s2 as &str, "s2");
+        format!("hello")
+    }
+}
+
+struct B(i32);
+
+impl FnOnce<(String, Box<str>)> for B {
+    type Output = String;
+    extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
+        assert_eq!(&s1 as &str, "s1");
+        assert_eq!(&s2 as &str, "s2");
+        format!("{}", self.0)
+    }
+}
+
+struct C(String);
+
+impl FnOnce<(String, Box<str>)> for C {
+    type Output = String;
+    extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
+        assert_eq!(&s1 as &str, "s1");
+        assert_eq!(&s2 as &str, "s2");
+        self.0
+    }
+}
+
+struct D(Box<String>);
+
+impl FnOnce<(String, Box<str>)> for D {
+    type Output = String;
+    extern "rust-call" fn call_once(self, (s1, s2): (String, Box<str>)) -> Self::Output {
+        assert_eq!(&s1 as &str, "s1");
+        assert_eq!(&s2 as &str, "s2");
+        *self.0
+    }
+}
+
+
+fn main() {
+    let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
+    let x = *(Box::new(A) as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
+    assert_eq!(x.call_once((s1, s2)), format!("hello"));
+    let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
+    let x = *(Box::new(B(42)) as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
+    assert_eq!(x.call_once((s1, s2)), format!("42"));
+    let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
+    let x = *(Box::new(C(format!("jumping fox")))
+              as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
+    assert_eq!(x.call_once((s1, s2)), format!("jumping fox"));
+    let (s1, s2) = (format!("s1"), format!("s2").into_boxed_str());
+    let x = *(Box::new(D(Box::new(format!("lazy dog"))))
+              as Box<dyn FnOnce<(String, Box<str>), Output = String>>);
+    assert_eq!(x.call_once((s1, s2)), format!("lazy dog"));
+}
diff --git a/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs b/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs
new file mode 100644
index 00000000000..3d67101e734
--- /dev/null
+++ b/src/test/run-pass-valgrind/unsized-locals/by-value-trait-objects.rs
@@ -0,0 +1,49 @@
+#![feature(unsized_locals)]
+
+pub trait Foo {
+    fn foo(self) -> String;
+}
+
+struct A;
+
+impl Foo for A {
+    fn foo(self) -> String {
+        format!("hello")
+    }
+}
+
+struct B(i32);
+
+impl Foo for B {
+    fn foo(self) -> String {
+        format!("{}", self.0)
+    }
+}
+
+struct C(String);
+
+impl Foo for C {
+    fn foo(self) -> String {
+        self.0
+    }
+}
+
+struct D(Box<String>);
+
+impl Foo for D {
+    fn foo(self) -> String {
+        *self.0
+    }
+}
+
+
+fn main() {
+    let x = *(Box::new(A) as Box<dyn Foo>);
+    assert_eq!(x.foo(), format!("hello"));
+    let x = *(Box::new(B(42)) as Box<dyn Foo>);
+    assert_eq!(x.foo(), format!("42"));
+    let x = *(Box::new(C(format!("jumping fox"))) as Box<dyn Foo>);
+    assert_eq!(x.foo(), format!("jumping fox"));
+    let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box<dyn Foo>);
+    assert_eq!(x.foo(), format!("lazy dog"));
+}
diff --git a/src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs b/src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs
index e1fda427b4e..2f275f88d96 100644
--- a/src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs
+++ b/src/test/run-pass-valgrind/unsized-locals/long-live-the-unsized-temporary.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 #![feature(unsized_locals)]
 
 use std::fmt;
diff --git a/src/test/run-pass/unsized-locals/autoderef.rs b/src/test/run-pass/unsized-locals/autoderef.rs
new file mode 100644
index 00000000000..885cd2b8360
--- /dev/null
+++ b/src/test/run-pass/unsized-locals/autoderef.rs
@@ -0,0 +1,47 @@
+#![feature(unsized_locals)]
+
+pub trait Foo {
+    fn foo(self) -> String;
+}
+
+impl Foo for [char] {
+    fn foo(self) -> String {
+        self.iter().collect()
+    }
+}
+
+impl Foo for str {
+    fn foo(self) -> String {
+        self.to_owned()
+    }
+}
+
+impl Foo for dyn FnMut() -> String {
+    fn foo(mut self) -> String {
+        self()
+    }
+}
+
+
+fn main() {
+    let x = *(Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>);
+    assert_eq!(&x.foo() as &str, "hello");
+
+    let x = Box::new(['h', 'e', 'l', 'l', 'o']) as Box<[char]>;
+    assert_eq!(&x.foo() as &str, "hello");
+
+    let x = "hello".to_owned().into_boxed_str();
+    assert_eq!(&x.foo() as &str, "hello");
+
+    let x = *("hello".to_owned().into_boxed_str());
+    assert_eq!(&x.foo() as &str, "hello");
+
+    let x = "hello".to_owned().into_boxed_str();
+    assert_eq!(&x.foo() as &str, "hello");
+
+    let x = *(Box::new(|| "hello".to_owned()) as Box<dyn FnMut() -> String>);
+    assert_eq!(&x.foo() as &str, "hello");
+
+    let x = Box::new(|| "hello".to_owned()) as Box<dyn FnMut() -> String>;
+    assert_eq!(&x.foo() as &str, "hello");
+}
diff --git a/src/test/run-pass/unsized-locals/by-value-trait-object-safety-withdefault.rs b/src/test/run-pass/unsized-locals/by-value-trait-object-safety-withdefault.rs
new file mode 100644
index 00000000000..e6e363f55a1
--- /dev/null
+++ b/src/test/run-pass/unsized-locals/by-value-trait-object-safety-withdefault.rs
@@ -0,0 +1,21 @@
+#![feature(unsized_locals)]
+
+pub trait Foo {
+    fn foo(self) -> String {
+        format!("hello")
+    }
+}
+
+struct A;
+
+impl Foo for A {}
+
+
+fn main() {
+    let x = *(Box::new(A) as Box<dyn Foo>);
+    assert_eq!(x.foo(), format!("hello"));
+
+    // I'm not sure whether we want this to work
+    let x = Box::new(A) as Box<dyn Foo>;
+    assert_eq!(x.foo(), format!("hello"));
+}
diff --git a/src/test/run-pass/unsized-locals/by-value-trait-object-safety.rs b/src/test/run-pass/unsized-locals/by-value-trait-object-safety.rs
new file mode 100644
index 00000000000..f19ff5b8de4
--- /dev/null
+++ b/src/test/run-pass/unsized-locals/by-value-trait-object-safety.rs
@@ -0,0 +1,23 @@
+#![feature(unsized_locals)]
+
+pub trait Foo {
+    fn foo(self) -> String;
+}
+
+struct A;
+
+impl Foo for A {
+    fn foo(self) -> String {
+        format!("hello")
+    }
+}
+
+
+fn main() {
+    let x = *(Box::new(A) as Box<dyn Foo>);
+    assert_eq!(x.foo(), format!("hello"));
+
+    // I'm not sure whether we want this to work
+    let x = Box::new(A) as Box<dyn Foo>;
+    assert_eq!(x.foo(), format!("hello"));
+}
diff --git a/src/test/run-pass/unsized-locals/reference-unsized-locals.rs b/src/test/run-pass/unsized-locals/reference-unsized-locals.rs
index 8b96c30940f..1560d25d4b0 100644
--- a/src/test/run-pass/unsized-locals/reference-unsized-locals.rs
+++ b/src/test/run-pass/unsized-locals/reference-unsized-locals.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 // run-pass
 
 #![feature(unsized_locals)]
diff --git a/src/test/run-pass/unsized-locals/simple-unsized-locals.rs b/src/test/run-pass/unsized-locals/simple-unsized-locals.rs
index 9643afaee62..05955919245 100644
--- a/src/test/run-pass/unsized-locals/simple-unsized-locals.rs
+++ b/src/test/run-pass/unsized-locals/simple-unsized-locals.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 // run-pass
 
 #![feature(unsized_locals)]
diff --git a/src/test/run-pass/unsized-locals/unsized-exprs.rs b/src/test/run-pass/unsized-locals/unsized-exprs.rs
index 06919a07c75..4b988f1e72d 100644
--- a/src/test/run-pass/unsized-locals/unsized-exprs.rs
+++ b/src/test/run-pass/unsized-locals/unsized-exprs.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 // run-pass
 
 #![feature(unsized_tuple_coercion, unsized_locals)]
diff --git a/src/test/run-pass/unsized-locals/unsized-parameters.rs b/src/test/run-pass/unsized-locals/unsized-parameters.rs
index 82036c5797d..3624154d5c4 100644
--- a/src/test/run-pass/unsized-locals/unsized-parameters.rs
+++ b/src/test/run-pass/unsized-locals/unsized-parameters.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 // run-pass
 
 #![feature(unsized_locals)]
diff --git a/src/test/ui/symbol-names/basic.stderr b/src/test/ui/symbol-names/basic.stderr
index eeeb1b5e34d..551c5bb4a75 100644
--- a/src/test/ui/symbol-names/basic.stderr
+++ b/src/test/ui/symbol-names/basic.stderr
@@ -1,4 +1,4 @@
-error: symbol-name(_ZN5basic4main17h2138d548fb9814b6E)
+error: symbol-name(_ZN5basic4main17h08bcaf310214ed52E)
   --> $DIR/basic.rs:13:1
    |
 LL | #[rustc_symbol_name] //~ ERROR _ZN5basic4main
diff --git a/src/test/ui/symbol-names/impl1.stderr b/src/test/ui/symbol-names/impl1.stderr
index edce6929695..73c8d7b9721 100644
--- a/src/test/ui/symbol-names/impl1.stderr
+++ b/src/test/ui/symbol-names/impl1.stderr
@@ -1,4 +1,4 @@
-error: symbol-name(_ZN5impl13foo3Foo3bar17h8da62e6147ff602fE)
+error: symbol-name(_ZN5impl13foo3Foo3bar17hc487d6ec13fe9124E)
   --> $DIR/impl1.rs:18:9
    |
 LL |         #[rustc_symbol_name] //~ ERROR _ZN5impl13foo3Foo3bar
@@ -10,7 +10,7 @@ error: item-path(foo::Foo::bar)
 LL |         #[rustc_item_path] //~ ERROR item-path(foo::Foo::bar)
    |         ^^^^^^^^^^^^^^^^^^
 
-error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h374cb8f6185db9b4E)
+error: symbol-name(_ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz17h38577281258e1527E)
   --> $DIR/impl1.rs:28:9
    |
 LL |         #[rustc_symbol_name] //~ ERROR _ZN5impl13bar33_$LT$impl$u20$impl1..foo..Foo$GT$3baz
diff --git a/src/test/ui/unsized-locals/borrow-after-move.nll.stderr b/src/test/ui/unsized-locals/borrow-after-move.nll.stderr
new file mode 100644
index 00000000000..a3cfcc89217
--- /dev/null
+++ b/src/test/ui/unsized-locals/borrow-after-move.nll.stderr
@@ -0,0 +1,51 @@
+error[E0382]: borrow of moved value: `x`
+  --> $DIR/borrow-after-move.rs:20:24
+   |
+LL |         let y = *x;
+   |                 -- value moved here
+LL |         drop_unsized(y);
+LL |         println!("{}", &x);
+   |                        ^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `y`
+  --> $DIR/borrow-after-move.rs:22:24
+   |
+LL |         drop_unsized(y);
+   |                      - value moved here
+...
+LL |         println!("{}", &y);
+   |                        ^^ value borrowed here after move
+   |
+   = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `x`
+  --> $DIR/borrow-after-move.rs:30:24
+   |
+LL |         let y = *x;
+   |                 -- value moved here
+LL |         y.foo();
+LL |         println!("{}", &x);
+   |                        ^^ value borrowed here after move
+
+error[E0382]: borrow of moved value: `y`
+  --> $DIR/borrow-after-move.rs:32:24
+   |
+LL |         y.foo();
+   |         - value moved here
+...
+LL |         println!("{}", &y);
+   |                        ^^ value borrowed here after move
+   |
+   = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: borrow of moved value: `x`
+  --> $DIR/borrow-after-move.rs:39:24
+   |
+LL |         x.foo();
+   |         - value moved here
+LL |         println!("{}", &x);
+   |                        ^^ value borrowed here after move
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/unsized-locals/borrow-after-move.rs b/src/test/ui/unsized-locals/borrow-after-move.rs
new file mode 100644
index 00000000000..587a2180c15
--- /dev/null
+++ b/src/test/ui/unsized-locals/borrow-after-move.rs
@@ -0,0 +1,42 @@
+#![feature(unsized_locals)]
+
+pub trait Foo {
+    fn foo(self) -> String;
+}
+
+impl Foo for str {
+    fn foo(self) -> String {
+        self.to_owned()
+    }
+}
+
+fn drop_unsized<T: ?Sized>(_: T) {}
+
+fn main() {
+    {
+        let x = "hello".to_owned().into_boxed_str();
+        let y = *x;
+        drop_unsized(y);
+        println!("{}", &x);
+        //~^ERROR use of moved value
+        println!("{}", &y);
+        //~^ERROR use of moved value
+    }
+
+    {
+        let x = "hello".to_owned().into_boxed_str();
+        let y = *x;
+        y.foo();
+        println!("{}", &x);
+        //~^ERROR use of moved value
+        println!("{}", &y);
+        //~^ERROR use of moved value
+    }
+
+    {
+        let x = "hello".to_owned().into_boxed_str();
+        x.foo();
+        println!("{}", &x);
+        //~^ERROR use of moved value
+    }
+}
diff --git a/src/test/ui/unsized-locals/borrow-after-move.stderr b/src/test/ui/unsized-locals/borrow-after-move.stderr
new file mode 100644
index 00000000000..8eea01f25c8
--- /dev/null
+++ b/src/test/ui/unsized-locals/borrow-after-move.stderr
@@ -0,0 +1,57 @@
+error[E0382]: use of moved value: `x`
+  --> $DIR/borrow-after-move.rs:20:25
+   |
+LL |         let y = *x;
+   |             - value moved here
+LL |         drop_unsized(y);
+LL |         println!("{}", &x);
+   |                         ^ value used here after move
+   |
+   = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `y`
+  --> $DIR/borrow-after-move.rs:22:25
+   |
+LL |         drop_unsized(y);
+   |                      - value moved here
+...
+LL |         println!("{}", &y);
+   |                         ^ value used here after move
+   |
+   = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/borrow-after-move.rs:30:25
+   |
+LL |         let y = *x;
+   |             - value moved here
+LL |         y.foo();
+LL |         println!("{}", &x);
+   |                         ^ value used here after move
+   |
+   = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `y`
+  --> $DIR/borrow-after-move.rs:32:25
+   |
+LL |         y.foo();
+   |         - value moved here
+...
+LL |         println!("{}", &y);
+   |                         ^ value used here after move
+   |
+   = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/borrow-after-move.rs:39:25
+   |
+LL |         x.foo();
+   |         - value moved here
+LL |         println!("{}", &x);
+   |                         ^ value used here after move
+   |
+   = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
+
+error: aborting due to 5 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/unsized-locals/by-value-trait-object-safety.rs b/src/test/ui/unsized-locals/by-value-trait-object-safety.rs
new file mode 100644
index 00000000000..8b24328bd38
--- /dev/null
+++ b/src/test/ui/unsized-locals/by-value-trait-object-safety.rs
@@ -0,0 +1,20 @@
+#![feature(unsized_locals)]
+
+pub trait Foo {
+    fn foo(self) -> String where Self: Sized;
+}
+
+struct A;
+
+impl Foo for A {
+    fn foo(self) -> String {
+        format!("hello")
+    }
+}
+
+
+fn main() {
+    let x = *(Box::new(A) as Box<dyn Foo>);
+    x.foo();
+    //~^ERROR the `foo` method cannot be invoked on a trait object
+}
diff --git a/src/test/ui/unsized-locals/by-value-trait-object-safety.stderr b/src/test/ui/unsized-locals/by-value-trait-object-safety.stderr
new file mode 100644
index 00000000000..7e9a2316be2
--- /dev/null
+++ b/src/test/ui/unsized-locals/by-value-trait-object-safety.stderr
@@ -0,0 +1,8 @@
+error: the `foo` method cannot be invoked on a trait object
+  --> $DIR/by-value-trait-object-safety.rs:18:7
+   |
+LL |     x.foo();
+   |       ^^^
+
+error: aborting due to previous error
+
diff --git a/src/test/ui/unsized-locals/double-move.nll.stderr b/src/test/ui/unsized-locals/double-move.nll.stderr
new file mode 100644
index 00000000000..0555a8944bf
--- /dev/null
+++ b/src/test/ui/unsized-locals/double-move.nll.stderr
@@ -0,0 +1,55 @@
+error[E0382]: use of moved value: `y`
+  --> $DIR/double-move.rs:20:22
+   |
+LL |         drop_unsized(y);
+   |                      - value moved here
+LL |         drop_unsized(y); //~ERROR use of moved value
+   |                      ^ value used here after move
+   |
+   = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/double-move.rs:26:22
+   |
+LL |         let _y = *x;
+   |                  -- value moved here
+LL |         drop_unsized(x); //~ERROR use of moved value
+   |                      ^ value used here after move
+
+error[E0382]: use of moved value: `*x`
+  --> $DIR/double-move.rs:32:18
+   |
+LL |         drop_unsized(x);
+   |                      - value moved here
+LL |         let _y = *x; //~ERROR use of moved value
+   |                  ^^ value used here after move
+
+error[E0382]: use of moved value: `y`
+  --> $DIR/double-move.rs:39:9
+   |
+LL |         y.foo();
+   |         - value moved here
+LL |         y.foo(); //~ERROR use of moved value
+   |         ^ value used here after move
+   |
+   = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `*x`
+  --> $DIR/double-move.rs:45:9
+   |
+LL |         let _y = *x;
+   |                  -- value moved here
+LL |         x.foo(); //~ERROR use of moved value
+   |         ^ value used here after move
+
+error[E0382]: use of moved value: `*x`
+  --> $DIR/double-move.rs:51:18
+   |
+LL |         x.foo();
+   |         - value moved here
+LL |         let _y = *x; //~ERROR use of moved value
+   |                  ^^ value used here after move
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/ui/unsized-locals/double-move.rs b/src/test/ui/unsized-locals/double-move.rs
new file mode 100644
index 00000000000..c3a50341bc9
--- /dev/null
+++ b/src/test/ui/unsized-locals/double-move.rs
@@ -0,0 +1,53 @@
+#![feature(unsized_locals)]
+
+pub trait Foo {
+    fn foo(self) -> String;
+}
+
+impl Foo for str {
+    fn foo(self) -> String {
+        self.to_owned()
+    }
+}
+
+fn drop_unsized<T: ?Sized>(_: T) {}
+
+fn main() {
+    {
+        let x = "hello".to_owned().into_boxed_str();
+        let y = *x;
+        drop_unsized(y);
+        drop_unsized(y); //~ERROR use of moved value
+    }
+
+    {
+        let x = "hello".to_owned().into_boxed_str();
+        let _y = *x;
+        drop_unsized(x); //~ERROR use of moved value
+    }
+
+    {
+        let x = "hello".to_owned().into_boxed_str();
+        drop_unsized(x);
+        let _y = *x; //~ERROR use of moved value
+    }
+
+    {
+        let x = "hello".to_owned().into_boxed_str();
+        let y = *x;
+        y.foo();
+        y.foo(); //~ERROR use of moved value
+    }
+
+    {
+        let x = "hello".to_owned().into_boxed_str();
+        let _y = *x;
+        x.foo(); //~ERROR use of moved value
+    }
+
+    {
+        let x = "hello".to_owned().into_boxed_str();
+        x.foo();
+        let _y = *x; //~ERROR use of moved value
+    }
+}
diff --git a/src/test/ui/unsized-locals/double-move.stderr b/src/test/ui/unsized-locals/double-move.stderr
new file mode 100644
index 00000000000..1009e913b7b
--- /dev/null
+++ b/src/test/ui/unsized-locals/double-move.stderr
@@ -0,0 +1,63 @@
+error[E0382]: use of moved value: `y`
+  --> $DIR/double-move.rs:20:22
+   |
+LL |         drop_unsized(y);
+   |                      - value moved here
+LL |         drop_unsized(y); //~ERROR use of moved value
+   |                      ^ value used here after move
+   |
+   = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `x`
+  --> $DIR/double-move.rs:26:22
+   |
+LL |         let _y = *x;
+   |             -- value moved here
+LL |         drop_unsized(x); //~ERROR use of moved value
+   |                      ^ value used here after move
+   |
+   = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `*x`
+  --> $DIR/double-move.rs:32:13
+   |
+LL |         drop_unsized(x);
+   |                      - value moved here
+LL |         let _y = *x; //~ERROR use of moved value
+   |             ^^ value used here after move
+   |
+   = note: move occurs because `x` has type `std::boxed::Box<str>`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `y`
+  --> $DIR/double-move.rs:39:9
+   |
+LL |         y.foo();
+   |         - value moved here
+LL |         y.foo(); //~ERROR use of moved value
+   |         ^ value used here after move
+   |
+   = note: move occurs because `y` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `*x`
+  --> $DIR/double-move.rs:45:9
+   |
+LL |         let _y = *x;
+   |             -- value moved here
+LL |         x.foo(); //~ERROR use of moved value
+   |         ^ value used here after move
+   |
+   = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
+
+error[E0382]: use of moved value: `*x`
+  --> $DIR/double-move.rs:51:13
+   |
+LL |         x.foo();
+   |         - value moved here
+LL |         let _y = *x; //~ERROR use of moved value
+   |             ^^ value used here after move
+   |
+   = note: move occurs because `*x` has type `str`, which does not implement the `Copy` trait
+
+error: aborting due to 6 previous errors
+
+For more information about this error, try `rustc --explain E0382`.
diff --git a/src/test/compile-fail/unsized-locals/unsized-exprs.rs b/src/test/ui/unsized-locals/unsized-exprs.rs
index a09ccbb407e..0cf93c78c4a 100644
--- a/src/test/compile-fail/unsized-locals/unsized-exprs.rs
+++ b/src/test/ui/unsized-locals/unsized-exprs.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 #![feature(unsized_tuple_coercion, unsized_locals)]
 
 struct A<X: ?Sized>(X);
diff --git a/src/test/ui/unsized-locals/unsized-exprs.stderr b/src/test/ui/unsized-locals/unsized-exprs.stderr
new file mode 100644
index 00000000000..eb201694177
--- /dev/null
+++ b/src/test/ui/unsized-locals/unsized-exprs.stderr
@@ -0,0 +1,25 @@
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/unsized-exprs.rs:22:26
+   |
+LL |     udrop::<(i32, [u8])>((42, *foo()));
+   |                          ^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `({integer}, [u8])`, the trait `std::marker::Sized` is not implemented for `[u8]`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = note: required because it appears within the type `({integer}, [u8])`
+   = note: tuples must have a statically known size to be initialized
+
+error[E0277]: the size for values of type `[u8]` cannot be known at compilation time
+  --> $DIR/unsized-exprs.rs:24:22
+   |
+LL |     udrop::<A<[u8]>>(A { 0: *foo() });
+   |                      ^^^^^^^^^^^^^^^ doesn't have a size known at compile-time
+   |
+   = help: within `A<[u8]>`, the trait `std::marker::Sized` is not implemented for `[u8]`
+   = note: to learn more, visit <https://doc.rust-lang.org/book/second-edition/ch19-04-advanced-types.html#dynamically-sized-types-and-the-sized-trait>
+   = note: required because it appears within the type `A<[u8]>`
+   = note: structs must have a statically known size to be initialized
+
+error: aborting due to 2 previous errors
+
+For more information about this error, try `rustc --explain E0277`.
diff --git a/src/test/ui/unsized-locals/unsized-exprs2.nll.stderr b/src/test/ui/unsized-locals/unsized-exprs2.nll.stderr
new file mode 100644
index 00000000000..675457b0db6
--- /dev/null
+++ b/src/test/ui/unsized-locals/unsized-exprs2.nll.stderr
@@ -0,0 +1,19 @@
+error[E0508]: cannot move out of type `[u8]`, a non-copy slice
+  --> $DIR/unsized-exprs2.rs:22:19
+   |
+LL |     udrop::<[u8]>(foo()[..]);
+   |                   ^^^^^^^^^ cannot move out of here
+
+error[E0507]: cannot move out of data in a `&` reference
+  --> $DIR/unsized-exprs2.rs:22:19
+   |
+LL |     udrop::<[u8]>(foo()[..]);
+   |                   ^^^^^^^^^
+   |                   |
+   |                   cannot move out of data in a `&` reference
+   |                   cannot move
+
+error: aborting due to 2 previous errors
+
+Some errors occurred: E0507, E0508.
+For more information about an error, try `rustc --explain E0507`.
diff --git a/src/test/compile-fail/unsized-locals/unsized-exprs2.rs b/src/test/ui/unsized-locals/unsized-exprs2.rs
index 40d6e54bd89..ae69893a835 100644
--- a/src/test/compile-fail/unsized-locals/unsized-exprs2.rs
+++ b/src/test/ui/unsized-locals/unsized-exprs2.rs
@@ -1,13 +1,3 @@
-// Copyright 2018 The Rust Project Developers. See the COPYRIGHT
-// file at the top-level directory of this distribution and at
-// http://rust-lang.org/COPYRIGHT.
-//
-// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
-// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
-// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
-// option. This file may not be copied, modified, or distributed
-// except according to those terms.
-
 #![feature(unsized_tuple_coercion, unsized_locals)]
 
 struct A<X: ?Sized>(X);
diff --git a/src/test/ui/unsized-locals/unsized-exprs2.stderr b/src/test/ui/unsized-locals/unsized-exprs2.stderr
new file mode 100644
index 00000000000..d7cb4bffb48
--- /dev/null
+++ b/src/test/ui/unsized-locals/unsized-exprs2.stderr
@@ -0,0 +1,9 @@
+error[E0507]: cannot move out of indexed content
+  --> $DIR/unsized-exprs2.rs:22:19
+   |
+LL |     udrop::<[u8]>(foo()[..]);
+   |                   ^^^^^^^^^ cannot move out of indexed content
+
+error: aborting due to previous error
+
+For more information about this error, try `rustc --explain E0507`.