mirror of
https://github.com/rust-lang/rust.git
synced 2025-06-05 11:48:30 +00:00
Auto merge of #107772 - compiler-errors:dyn-star-backend-is-ptr, r=eholk
Make `dyn*`'s value backend type a pointer One tweak on top of Ralf's commit should fix using `usize` as a `dyn*`-coercible type, and should fix when we're using various other pointer types when LLVM opaque pointers is disabled. r? `@eholk` but feel free to reassign cc https://github.com/rust-lang/rust/pull/107728#issuecomment-1421231823 `@RalfJung`
This commit is contained in:
commit
73f40197ec
@ -329,7 +329,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
|
|||||||
) -> &'a Type {
|
) -> &'a Type {
|
||||||
// HACK(eddyb) special-case fat pointers until LLVM removes
|
// HACK(eddyb) special-case fat pointers until LLVM removes
|
||||||
// pointee types, to avoid bitcasting every `OperandRef::deref`.
|
// pointee types, to avoid bitcasting every `OperandRef::deref`.
|
||||||
match self.ty.kind() {
|
match *self.ty.kind() {
|
||||||
ty::Ref(..) | ty::RawPtr(_) => {
|
ty::Ref(..) | ty::RawPtr(_) => {
|
||||||
return self.field(cx, index).llvm_type(cx);
|
return self.field(cx, index).llvm_type(cx);
|
||||||
}
|
}
|
||||||
@ -339,6 +339,11 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
|
|||||||
let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
|
let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
|
||||||
return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
|
return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
|
||||||
}
|
}
|
||||||
|
// `dyn* Trait` has the same ABI as `*mut dyn Trait`
|
||||||
|
ty::Dynamic(bounds, region, ty::DynStar) => {
|
||||||
|
let ptr_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_dynamic(bounds, region, ty::Dyn));
|
||||||
|
return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
|
||||||
|
}
|
||||||
_ => {}
|
_ => {}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -39,7 +39,7 @@ use rustc_session::Session;
|
|||||||
use rustc_span::symbol::sym;
|
use rustc_span::symbol::sym;
|
||||||
use rustc_span::Symbol;
|
use rustc_span::Symbol;
|
||||||
use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
|
||||||
use rustc_target::abi::{Align, Size, VariantIdx};
|
use rustc_target::abi::{Align, VariantIdx};
|
||||||
|
|
||||||
use std::collections::BTreeSet;
|
use std::collections::BTreeSet;
|
||||||
use std::time::{Duration, Instant};
|
use std::time::{Duration, Instant};
|
||||||
@ -273,12 +273,13 @@ pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
|
|||||||
matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
|
matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
|
||||||
"destination type must be a dyn*"
|
"destination type must be a dyn*"
|
||||||
);
|
);
|
||||||
// FIXME(dyn-star): this is probably not the best way to check if this is
|
// FIXME(dyn-star): We can remove this when all supported LLVMs use opaque ptrs only.
|
||||||
// a pointer, and really we should ensure that the value is a suitable
|
let unit_ptr = bx.cx().type_ptr_to(bx.cx().type_struct(&[], false));
|
||||||
// pointer earlier in the compilation process.
|
let src = match bx.cx().type_kind(bx.cx().backend_type(src_ty_and_layout)) {
|
||||||
let src = match src_ty_and_layout.pointee_info_at(bx.cx(), Size::ZERO) {
|
TypeKind::Pointer => bx.pointercast(src, unit_ptr),
|
||||||
Some(_) => bx.ptrtoint(src, bx.cx().type_isize()),
|
TypeKind::Integer => bx.inttoptr(src, unit_ptr),
|
||||||
None => bx.bitcast(src, bx.type_isize()),
|
// FIXME(dyn-star): We probably have to do a bitcast first, then inttoptr.
|
||||||
|
kind => bug!("unexpected TypeKind for left-hand side of `dyn*` cast: {kind:?}"),
|
||||||
};
|
};
|
||||||
(src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info))
|
(src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info))
|
||||||
}
|
}
|
||||||
|
@ -452,86 +452,84 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||||||
args1 = [place.llval];
|
args1 = [place.llval];
|
||||||
&args1[..]
|
&args1[..]
|
||||||
};
|
};
|
||||||
let (drop_fn, fn_abi) = match ty.kind() {
|
let (drop_fn, fn_abi) =
|
||||||
// FIXME(eddyb) perhaps move some of this logic into
|
match ty.kind() {
|
||||||
// `Instance::resolve_drop_in_place`?
|
// FIXME(eddyb) perhaps move some of this logic into
|
||||||
ty::Dynamic(_, _, ty::Dyn) => {
|
// `Instance::resolve_drop_in_place`?
|
||||||
// IN THIS ARM, WE HAVE:
|
ty::Dynamic(_, _, ty::Dyn) => {
|
||||||
// ty = *mut (dyn Trait)
|
// IN THIS ARM, WE HAVE:
|
||||||
// which is: exists<T> ( *mut T, Vtable<T: Trait> )
|
// ty = *mut (dyn Trait)
|
||||||
// args[0] args[1]
|
// which is: exists<T> ( *mut T, Vtable<T: Trait> )
|
||||||
//
|
// args[0] args[1]
|
||||||
// args = ( Data, Vtable )
|
//
|
||||||
// |
|
// args = ( Data, Vtable )
|
||||||
// v
|
// |
|
||||||
// /-------\
|
// v
|
||||||
// | ... |
|
// /-------\
|
||||||
// \-------/
|
// | ... |
|
||||||
//
|
// \-------/
|
||||||
let virtual_drop = Instance {
|
//
|
||||||
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
|
let virtual_drop = Instance {
|
||||||
substs: drop_fn.substs,
|
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
|
||||||
};
|
substs: drop_fn.substs,
|
||||||
debug!("ty = {:?}", ty);
|
};
|
||||||
debug!("drop_fn = {:?}", drop_fn);
|
debug!("ty = {:?}", ty);
|
||||||
debug!("args = {:?}", args);
|
debug!("drop_fn = {:?}", drop_fn);
|
||||||
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
debug!("args = {:?}", args);
|
||||||
let vtable = args[1];
|
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||||
// Truncate vtable off of args list
|
let vtable = args[1];
|
||||||
args = &args[..1];
|
// Truncate vtable off of args list
|
||||||
(
|
args = &args[..1];
|
||||||
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
|
(
|
||||||
.get_fn(bx, vtable, ty, &fn_abi),
|
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
|
||||||
fn_abi,
|
.get_fn(bx, vtable, ty, &fn_abi),
|
||||||
)
|
fn_abi,
|
||||||
}
|
)
|
||||||
ty::Dynamic(_, _, ty::DynStar) => {
|
}
|
||||||
// IN THIS ARM, WE HAVE:
|
ty::Dynamic(_, _, ty::DynStar) => {
|
||||||
// ty = *mut (dyn* Trait)
|
// IN THIS ARM, WE HAVE:
|
||||||
// which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
|
// ty = *mut (dyn* Trait)
|
||||||
//
|
// which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
|
||||||
// args = [ * ]
|
//
|
||||||
// |
|
// args = [ * ]
|
||||||
// v
|
// |
|
||||||
// ( Data, Vtable )
|
// v
|
||||||
// |
|
// ( Data, Vtable )
|
||||||
// v
|
// |
|
||||||
// /-------\
|
// v
|
||||||
// | ... |
|
// /-------\
|
||||||
// \-------/
|
// | ... |
|
||||||
//
|
// \-------/
|
||||||
//
|
//
|
||||||
// WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
|
//
|
||||||
//
|
// WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
|
||||||
// data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
|
//
|
||||||
// vtable = (*args[0]).1 // loads the vtable out
|
// data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
|
||||||
// (data, vtable) // an equivalent Rust `*mut dyn Trait`
|
// vtable = (*args[0]).1 // loads the vtable out
|
||||||
//
|
// (data, vtable) // an equivalent Rust `*mut dyn Trait`
|
||||||
// SO THEN WE CAN USE THE ABOVE CODE.
|
//
|
||||||
let virtual_drop = Instance {
|
// SO THEN WE CAN USE THE ABOVE CODE.
|
||||||
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
|
let virtual_drop = Instance {
|
||||||
substs: drop_fn.substs,
|
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
|
||||||
};
|
substs: drop_fn.substs,
|
||||||
debug!("ty = {:?}", ty);
|
};
|
||||||
debug!("drop_fn = {:?}", drop_fn);
|
debug!("ty = {:?}", ty);
|
||||||
debug!("args = {:?}", args);
|
debug!("drop_fn = {:?}", drop_fn);
|
||||||
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
debug!("args = {:?}", args);
|
||||||
let data = args[0];
|
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
|
||||||
let data_ty = bx.cx().backend_type(place.layout);
|
let meta_ptr = place.project_field(bx, 1);
|
||||||
let vtable_ptr =
|
let meta = bx.load_operand(meta_ptr);
|
||||||
bx.gep(data_ty, data, &[bx.cx().const_i32(0), bx.cx().const_i32(1)]);
|
// Truncate vtable off of args list
|
||||||
let vtable = bx.load(bx.type_i8p(), vtable_ptr, abi::Align::ONE);
|
args = &args[..1];
|
||||||
// Truncate vtable off of args list
|
debug!("args' = {:?}", args);
|
||||||
args = &args[..1];
|
(
|
||||||
debug!("args' = {:?}", args);
|
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
|
||||||
(
|
.get_fn(bx, meta.immediate(), ty, &fn_abi),
|
||||||
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
|
fn_abi,
|
||||||
.get_fn(bx, vtable, ty, &fn_abi),
|
)
|
||||||
fn_abi,
|
}
|
||||||
)
|
_ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
|
||||||
}
|
};
|
||||||
_ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
|
|
||||||
};
|
|
||||||
helper.do_call(
|
helper.do_call(
|
||||||
self,
|
self,
|
||||||
bx,
|
bx,
|
||||||
|
@ -770,7 +770,7 @@ where
|
|||||||
|
|
||||||
ty::Dynamic(_, _, ty::DynStar) => {
|
ty::Dynamic(_, _, ty::DynStar) => {
|
||||||
if i == 0 {
|
if i == 0 {
|
||||||
TyMaybeWithLayout::Ty(tcx.types.usize)
|
TyMaybeWithLayout::Ty(tcx.mk_mut_ptr(tcx.types.unit))
|
||||||
} else if i == 1 {
|
} else if i == 1 {
|
||||||
// FIXME(dyn-star) same FIXME as above applies here too
|
// FIXME(dyn-star) same FIXME as above applies here too
|
||||||
TyMaybeWithLayout::Ty(
|
TyMaybeWithLayout::Ty(
|
||||||
|
@ -193,7 +193,7 @@ fn layout_of_uncached<'tcx>(
|
|||||||
}
|
}
|
||||||
|
|
||||||
ty::Dynamic(_, _, ty::DynStar) => {
|
ty::Dynamic(_, _, ty::DynStar) => {
|
||||||
let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false));
|
let mut data = scalar_unit(Pointer(AddressSpace::DATA));
|
||||||
data.valid_range_mut().start = 0;
|
data.valid_range_mut().start = 0;
|
||||||
let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
|
let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
|
||||||
vtable.valid_range_mut().start = 1;
|
vtable.valid_range_mut().start = 1;
|
||||||
|
@ -26,11 +26,9 @@ pub enum DynKind {
|
|||||||
Dyn,
|
Dyn,
|
||||||
/// A sized `dyn* Trait` object
|
/// A sized `dyn* Trait` object
|
||||||
///
|
///
|
||||||
/// These objects are represented as a `(data, vtable)` pair where `data` is a ptr-sized value
|
/// These objects are represented as a `(data, vtable)` pair where `data` is a value of some
|
||||||
/// (often a pointer to the real object, but not necessarily) and `vtable` is a pointer to
|
/// ptr-sized and ptr-aligned dynamically determined type `T` and `vtable` is a pointer to the
|
||||||
/// the vtable for `dyn* Trait`. The representation is essentially the same as `&dyn Trait`
|
/// vtable of `impl T for Trait`. This allows a `dyn*` object to be treated agnostically with
|
||||||
/// or similar, but the drop function included in the vtable is responsible for freeing the
|
|
||||||
/// underlying storage if needed. This allows a `dyn*` object to be treated agnostically with
|
|
||||||
/// respect to whether it points to a `Box<T>`, `Rc<T>`, etc.
|
/// respect to whether it points to a `Box<T>`, `Rc<T>`, etc.
|
||||||
DynStar,
|
DynStar,
|
||||||
}
|
}
|
||||||
|
@ -1,6 +1,7 @@
|
|||||||
// compile-flags: -O -C no-prepopulate-passes
|
// compile-flags: -O -C no-prepopulate-passes
|
||||||
|
|
||||||
#![crate_type = "lib"]
|
#![crate_type = "lib"]
|
||||||
|
#![feature(dyn_star)]
|
||||||
|
|
||||||
use std::mem::MaybeUninit;
|
use std::mem::MaybeUninit;
|
||||||
use std::num::NonZeroU64;
|
use std::num::NonZeroU64;
|
||||||
@ -279,3 +280,11 @@ pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
|
|||||||
pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
|
pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
|
||||||
x
|
x
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// CHECK: { {{\{\}\*|ptr}}, {{.+}} } @dyn_star({{\{\}\*|ptr}} noundef %x.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %x.1)
|
||||||
|
// Expect an ABI something like `{ {}*, [3 x i64]* }`, but that's hard to match on generically,
|
||||||
|
// so do like the `trait_box` test and just match on `{{.+}}` for the vtable.
|
||||||
|
#[no_mangle]
|
||||||
|
pub fn dyn_star(x: dyn* Drop) -> dyn* Drop {
|
||||||
|
x
|
||||||
|
}
|
||||||
|
23
tests/ui/dyn-star/llvm-old-style-ptrs.rs
Normal file
23
tests/ui/dyn-star/llvm-old-style-ptrs.rs
Normal file
@ -0,0 +1,23 @@
|
|||||||
|
// run-pass
|
||||||
|
// compile-flags: -Copt-level=0 -Cllvm-args=-opaque-pointers=0
|
||||||
|
|
||||||
|
// (opaque-pointers flag is called force-opaque-pointers in LLVM 13...)
|
||||||
|
// min-llvm-version: 14.0
|
||||||
|
|
||||||
|
// This test can be removed once non-opaque pointers are gone from LLVM, maybe.
|
||||||
|
|
||||||
|
#![feature(dyn_star, pointer_like_trait)]
|
||||||
|
#![allow(incomplete_features)]
|
||||||
|
|
||||||
|
use std::fmt::Debug;
|
||||||
|
use std::marker::PointerLike;
|
||||||
|
|
||||||
|
fn make_dyn_star<'a>(t: impl PointerLike + Debug + 'a) -> dyn* Debug + 'a {
|
||||||
|
t as _
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
println!("{:?}", make_dyn_star(Box::new(1i32)));
|
||||||
|
println!("{:?}", make_dyn_star(2usize));
|
||||||
|
println!("{:?}", make_dyn_star((3usize,)));
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user