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
This commit is contained in:
bors 2018-10-27 19:29:35 +00:00
commit cae6efc37d
46 changed files with 870 additions and 171 deletions

View File

@ -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

View File

@ -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);
}

View File

@ -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>(

View File

@ -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(..) |

View File

@ -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) => {

View File

@ -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);
}

View File

@ -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(||

View File

@ -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()
)
}

View File

@ -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)
}
}

View File

@ -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));

View File

@ -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
}

View File

@ -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);

View File

@ -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)
})
});

View File

@ -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);
}
}

View File

@ -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);
}

View File

@ -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

View File

@ -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(..) |

View File

@ -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,

View File

@ -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(..) |

View File

@ -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(

View File

@ -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"));
}

View File

@ -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"));
}

View File

@ -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"));
}

View File

@ -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;

View File

@ -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");
}

View File

@ -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"));
}

View File

@ -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"));
}

View File

@ -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)]

View File

@ -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)]

View File

@ -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)]

View File

@ -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)]

View File

@ -1,4 +1,4 @@
error: symbol-name(_ZN5basic4main17h2138d548fb9814b6E)
error: symbol-name(_ZN5basic4main17h08bcaf310214ed52E)
--> $DIR/basic.rs:13:1
|
LL | #[rustc_symbol_name] //~ ERROR _ZN5basic4main

View File

@ -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

View File

@ -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`.

View File

@ -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
}
}

View File

@ -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`.

View File

@ -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
}

View File

@ -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

View File

@ -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`.

View File

@ -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
}
}

View File

@ -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`.

View File

@ -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);

View File

@ -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`.

View File

@ -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`.

View File

@ -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);

View File

@ -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`.