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 7a5fe5b7f28cd..6f7cf754ae083 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`, instead of `Box` 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 7e5d19850f48d..0c38cb10a2320 100644 --- a/src/librustc/ich/impls_ty.rs +++ b/src/librustc/ich/impls_ty.rs @@ -1007,6 +1007,9 @@ impl<'a, 'gcx> HashStable> 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 3d205215d64c6..041565c8b5a07 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), + /// `::method` where `method` receives unsizeable `self: Self`. + VtableShim(DefId), + /// \::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> { + 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 48ba69fee1cfd..f8fc2cc83034f 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 62827ea20c31d..ba5b714a0e7d9 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 7b93d3e795ed8..7c7662a88de53 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` 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 a9119d49e8b20..a4c7a7123b964 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 4b4ccb3b600b3..7300bac96182b 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 c08937fa9b916..c9b464fd8f3dd 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 826df82193a31..241f7989e1681 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 26969e24f0883..f4aede55ce1a6 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 272196afa6f92..03244c18ac3e4 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 29c2e71960c2c..d38f343d01f34 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 68e30227185c0..d98b7869ae98e 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 dab9b147cc070..91c1ccbe00213 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 c1e80234a7750..0d95b0c7bbc0c 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 faeeb24c6c267..ee84e49022f1b 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 e8c482e836ff4..8c6966691328a 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 3a1108bb16983..f0a35ca7adbd2 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 6c32690cdb340..7061504cd0ae7 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 0000000000000..7f365ce2bbaf3 --- /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 { + 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); + +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>); + assert_eq!(x.call_once(()), format!("hello")); + let x = *(Box::new(B(42)) as Box>); + assert_eq!(x.call_once(()), format!("42")); + let x = *(Box::new(C(format!("jumping fox"))) as Box>); + assert_eq!(x.call_once(()), format!("jumping fox")); + let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box>); + 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 0000000000000..a78b897d19414 --- /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 { + type Output; + extern "rust-call" fn call_once(self, args: Args) -> Self::Output; +} + +struct A; + +impl FnOnce<(String, Box)> for A { + type Output = String; + extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> Self::Output { + assert_eq!(&s1 as &str, "s1"); + assert_eq!(&s2 as &str, "s2"); + format!("hello") + } +} + +struct B(i32); + +impl FnOnce<(String, Box)> for B { + type Output = String; + extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> Self::Output { + assert_eq!(&s1 as &str, "s1"); + assert_eq!(&s2 as &str, "s2"); + format!("{}", self.0) + } +} + +struct C(String); + +impl FnOnce<(String, Box)> for C { + type Output = String; + extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> Self::Output { + assert_eq!(&s1 as &str, "s1"); + assert_eq!(&s2 as &str, "s2"); + self.0 + } +} + +struct D(Box); + +impl FnOnce<(String, Box)> for D { + type Output = String; + extern "rust-call" fn call_once(self, (s1, s2): (String, Box)) -> 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), 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), 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), 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), 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 0000000000000..3d67101e734c7 --- /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); + +impl Foo for D { + fn foo(self) -> String { + *self.0 + } +} + + +fn main() { + let x = *(Box::new(A) as Box); + assert_eq!(x.foo(), format!("hello")); + let x = *(Box::new(B(42)) as Box); + assert_eq!(x.foo(), format!("42")); + let x = *(Box::new(C(format!("jumping fox"))) as Box); + assert_eq!(x.foo(), format!("jumping fox")); + let x = *(Box::new(D(Box::new(format!("lazy dog")))) as Box); + 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 e1fda427b4e73..2f275f88d963e 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 or the MIT license -// , 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 0000000000000..885cd2b836080 --- /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 String>); + assert_eq!(&x.foo() as &str, "hello"); + + let x = Box::new(|| "hello".to_owned()) as Box 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 0000000000000..e6e363f55a1a6 --- /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); + assert_eq!(x.foo(), format!("hello")); + + // I'm not sure whether we want this to work + let x = Box::new(A) as Box; + 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 0000000000000..f19ff5b8de462 --- /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); + assert_eq!(x.foo(), format!("hello")); + + // I'm not sure whether we want this to work + let x = Box::new(A) as Box; + 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 8b96c30940f07..1560d25d4b0de 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 or the MIT license -// , 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 9643afaee6276..059559192456d 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 or the MIT license -// , 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 06919a07c756b..4b988f1e72d5a 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 or the MIT license -// , 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 82036c5797d79..3624154d5c44c 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 or the MIT license -// , 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 eeeb1b5e34d8b..551c5bb4a7591 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 edce692969556..73c8d7b9721c6 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 0000000000000..a3cfcc8921766 --- /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 0000000000000..587a2180c1558 --- /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) {} + +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 0000000000000..8eea01f25c865 --- /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 0000000000000..8b24328bd3854 --- /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); + 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 0000000000000..7e9a2316be2bf --- /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 0000000000000..0555a8944bf94 --- /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 0000000000000..c3a50341bc962 --- /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) {} + +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 0000000000000..1009e913b7b67 --- /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`, 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 similarity index 52% rename from src/test/compile-fail/unsized-locals/unsized-exprs.rs rename to src/test/ui/unsized-locals/unsized-exprs.rs index a09ccbb407e98..0cf93c78c4abe 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 or the MIT license -// , 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); 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 0000000000000..eb2016941770c --- /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 + = 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 { 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 + = 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 0000000000000..675457b0db6bb --- /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 similarity index 53% rename from src/test/compile-fail/unsized-locals/unsized-exprs2.rs rename to src/test/ui/unsized-locals/unsized-exprs2.rs index 40d6e54bd892f..ae69893a83577 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 or the MIT license -// , 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); 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 0000000000000..d7cb4bffb483d --- /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`.