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:
commit
cae6efc37d
@ -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
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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>(
|
||||
|
@ -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(..) |
|
||||
|
@ -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) => {
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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(||
|
||||
|
@ -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()
|
||||
)
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
}
|
||||
|
@ -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));
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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);
|
||||
|
@ -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)
|
||||
})
|
||||
});
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -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);
|
||||
}
|
||||
|
@ -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
|
||||
|
@ -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(..) |
|
||||
|
@ -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,
|
||||
|
@ -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(..) |
|
||||
|
@ -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(
|
||||
|
@ -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"));
|
||||
}
|
@ -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"));
|
||||
}
|
@ -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"));
|
||||
}
|
@ -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;
|
||||
|
47
src/test/run-pass/unsized-locals/autoderef.rs
Normal file
47
src/test/run-pass/unsized-locals/autoderef.rs
Normal 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");
|
||||
}
|
@ -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"));
|
||||
}
|
@ -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"));
|
||||
}
|
@ -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)]
|
||||
|
@ -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)]
|
||||
|
@ -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)]
|
||||
|
@ -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)]
|
||||
|
@ -1,4 +1,4 @@
|
||||
error: symbol-name(_ZN5basic4main17h2138d548fb9814b6E)
|
||||
error: symbol-name(_ZN5basic4main17h08bcaf310214ed52E)
|
||||
--> $DIR/basic.rs:13:1
|
||||
|
|
||||
LL | #[rustc_symbol_name] //~ ERROR _ZN5basic4main
|
||||
|
@ -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
|
||||
|
51
src/test/ui/unsized-locals/borrow-after-move.nll.stderr
Normal file
51
src/test/ui/unsized-locals/borrow-after-move.nll.stderr
Normal 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`.
|
42
src/test/ui/unsized-locals/borrow-after-move.rs
Normal file
42
src/test/ui/unsized-locals/borrow-after-move.rs
Normal 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
|
||||
}
|
||||
}
|
57
src/test/ui/unsized-locals/borrow-after-move.stderr
Normal file
57
src/test/ui/unsized-locals/borrow-after-move.stderr
Normal 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`.
|
20
src/test/ui/unsized-locals/by-value-trait-object-safety.rs
Normal file
20
src/test/ui/unsized-locals/by-value-trait-object-safety.rs
Normal 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
|
||||
}
|
@ -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
|
||||
|
55
src/test/ui/unsized-locals/double-move.nll.stderr
Normal file
55
src/test/ui/unsized-locals/double-move.nll.stderr
Normal 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`.
|
53
src/test/ui/unsized-locals/double-move.rs
Normal file
53
src/test/ui/unsized-locals/double-move.rs
Normal 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
|
||||
}
|
||||
}
|
63
src/test/ui/unsized-locals/double-move.stderr
Normal file
63
src/test/ui/unsized-locals/double-move.stderr
Normal 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`.
|
@ -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);
|
25
src/test/ui/unsized-locals/unsized-exprs.stderr
Normal file
25
src/test/ui/unsized-locals/unsized-exprs.stderr
Normal 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`.
|
19
src/test/ui/unsized-locals/unsized-exprs2.nll.stderr
Normal file
19
src/test/ui/unsized-locals/unsized-exprs2.nll.stderr
Normal 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`.
|
@ -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);
|
9
src/test/ui/unsized-locals/unsized-exprs2.stderr
Normal file
9
src/test/ui/unsized-locals/unsized-exprs2.stderr
Normal 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`.
|
Loading…
Reference in New Issue
Block a user