Skip to content

Commit 73f4019

Browse files
committed
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 #107728 (comment) `@RalfJung`
2 parents fcdbd1c + 7f798c2 commit 73f4019

File tree

8 files changed

+129
-95
lines changed

8 files changed

+129
-95
lines changed

compiler/rustc_codegen_llvm/src/type_of.rs

+6-1
Original file line numberDiff line numberDiff line change
@@ -329,7 +329,7 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
329329
) -> &'a Type {
330330
// HACK(eddyb) special-case fat pointers until LLVM removes
331331
// pointee types, to avoid bitcasting every `OperandRef::deref`.
332-
match self.ty.kind() {
332+
match *self.ty.kind() {
333333
ty::Ref(..) | ty::RawPtr(_) => {
334334
return self.field(cx, index).llvm_type(cx);
335335
}
@@ -339,6 +339,11 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> {
339339
let ptr_ty = cx.tcx.mk_mut_ptr(self.ty.boxed_ty());
340340
return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
341341
}
342+
// `dyn* Trait` has the same ABI as `*mut dyn Trait`
343+
ty::Dynamic(bounds, region, ty::DynStar) => {
344+
let ptr_ty = cx.tcx.mk_mut_ptr(cx.tcx.mk_dynamic(bounds, region, ty::Dyn));
345+
return cx.layout_of(ptr_ty).scalar_pair_element_llvm_type(cx, index, immediate);
346+
}
342347
_ => {}
343348
}
344349

compiler/rustc_codegen_ssa/src/base.rs

+8-7
Original file line numberDiff line numberDiff line change
@@ -39,7 +39,7 @@ use rustc_session::Session;
3939
use rustc_span::symbol::sym;
4040
use rustc_span::Symbol;
4141
use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType};
42-
use rustc_target::abi::{Align, Size, VariantIdx};
42+
use rustc_target::abi::{Align, VariantIdx};
4343

4444
use std::collections::BTreeSet;
4545
use std::time::{Duration, Instant};
@@ -273,12 +273,13 @@ pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>(
273273
matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)),
274274
"destination type must be a dyn*"
275275
);
276-
// FIXME(dyn-star): this is probably not the best way to check if this is
277-
// a pointer, and really we should ensure that the value is a suitable
278-
// pointer earlier in the compilation process.
279-
let src = match src_ty_and_layout.pointee_info_at(bx.cx(), Size::ZERO) {
280-
Some(_) => bx.ptrtoint(src, bx.cx().type_isize()),
281-
None => bx.bitcast(src, bx.type_isize()),
276+
// FIXME(dyn-star): We can remove this when all supported LLVMs use opaque ptrs only.
277+
let unit_ptr = bx.cx().type_ptr_to(bx.cx().type_struct(&[], false));
278+
let src = match bx.cx().type_kind(bx.cx().backend_type(src_ty_and_layout)) {
279+
TypeKind::Pointer => bx.pointercast(src, unit_ptr),
280+
TypeKind::Integer => bx.inttoptr(src, unit_ptr),
281+
// FIXME(dyn-star): We probably have to do a bitcast first, then inttoptr.
282+
kind => bug!("unexpected TypeKind for left-hand side of `dyn*` cast: {kind:?}"),
282283
};
283284
(src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info))
284285
}

compiler/rustc_codegen_ssa/src/mir/block.rs

+78-80
Original file line numberDiff line numberDiff line change
@@ -452,86 +452,84 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
452452
args1 = [place.llval];
453453
&args1[..]
454454
};
455-
let (drop_fn, fn_abi) = match ty.kind() {
456-
// FIXME(eddyb) perhaps move some of this logic into
457-
// `Instance::resolve_drop_in_place`?
458-
ty::Dynamic(_, _, ty::Dyn) => {
459-
// IN THIS ARM, WE HAVE:
460-
// ty = *mut (dyn Trait)
461-
// which is: exists<T> ( *mut T, Vtable<T: Trait> )
462-
// args[0] args[1]
463-
//
464-
// args = ( Data, Vtable )
465-
// |
466-
// v
467-
// /-------\
468-
// | ... |
469-
// \-------/
470-
//
471-
let virtual_drop = Instance {
472-
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
473-
substs: drop_fn.substs,
474-
};
475-
debug!("ty = {:?}", ty);
476-
debug!("drop_fn = {:?}", drop_fn);
477-
debug!("args = {:?}", args);
478-
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
479-
let vtable = args[1];
480-
// Truncate vtable off of args list
481-
args = &args[..1];
482-
(
483-
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
484-
.get_fn(bx, vtable, ty, &fn_abi),
485-
fn_abi,
486-
)
487-
}
488-
ty::Dynamic(_, _, ty::DynStar) => {
489-
// IN THIS ARM, WE HAVE:
490-
// ty = *mut (dyn* Trait)
491-
// which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
492-
//
493-
// args = [ * ]
494-
// |
495-
// v
496-
// ( Data, Vtable )
497-
// |
498-
// v
499-
// /-------\
500-
// | ... |
501-
// \-------/
502-
//
503-
//
504-
// WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
505-
//
506-
// data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
507-
// vtable = (*args[0]).1 // loads the vtable out
508-
// (data, vtable) // an equivalent Rust `*mut dyn Trait`
509-
//
510-
// SO THEN WE CAN USE THE ABOVE CODE.
511-
let virtual_drop = Instance {
512-
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
513-
substs: drop_fn.substs,
514-
};
515-
debug!("ty = {:?}", ty);
516-
debug!("drop_fn = {:?}", drop_fn);
517-
debug!("args = {:?}", args);
518-
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
519-
let data = args[0];
520-
let data_ty = bx.cx().backend_type(place.layout);
521-
let vtable_ptr =
522-
bx.gep(data_ty, data, &[bx.cx().const_i32(0), bx.cx().const_i32(1)]);
523-
let vtable = bx.load(bx.type_i8p(), vtable_ptr, abi::Align::ONE);
524-
// Truncate vtable off of args list
525-
args = &args[..1];
526-
debug!("args' = {:?}", args);
527-
(
528-
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
529-
.get_fn(bx, vtable, ty, &fn_abi),
530-
fn_abi,
531-
)
532-
}
533-
_ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
534-
};
455+
let (drop_fn, fn_abi) =
456+
match ty.kind() {
457+
// FIXME(eddyb) perhaps move some of this logic into
458+
// `Instance::resolve_drop_in_place`?
459+
ty::Dynamic(_, _, ty::Dyn) => {
460+
// IN THIS ARM, WE HAVE:
461+
// ty = *mut (dyn Trait)
462+
// which is: exists<T> ( *mut T, Vtable<T: Trait> )
463+
// args[0] args[1]
464+
//
465+
// args = ( Data, Vtable )
466+
// |
467+
// v
468+
// /-------\
469+
// | ... |
470+
// \-------/
471+
//
472+
let virtual_drop = Instance {
473+
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
474+
substs: drop_fn.substs,
475+
};
476+
debug!("ty = {:?}", ty);
477+
debug!("drop_fn = {:?}", drop_fn);
478+
debug!("args = {:?}", args);
479+
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
480+
let vtable = args[1];
481+
// Truncate vtable off of args list
482+
args = &args[..1];
483+
(
484+
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
485+
.get_fn(bx, vtable, ty, &fn_abi),
486+
fn_abi,
487+
)
488+
}
489+
ty::Dynamic(_, _, ty::DynStar) => {
490+
// IN THIS ARM, WE HAVE:
491+
// ty = *mut (dyn* Trait)
492+
// which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
493+
//
494+
// args = [ * ]
495+
// |
496+
// v
497+
// ( Data, Vtable )
498+
// |
499+
// v
500+
// /-------\
501+
// | ... |
502+
// \-------/
503+
//
504+
//
505+
// WE CAN CONVERT THIS INTO THE ABOVE LOGIC BY DOING
506+
//
507+
// data = &(*args[0]).0 // gives a pointer to Data above (really the same pointer)
508+
// vtable = (*args[0]).1 // loads the vtable out
509+
// (data, vtable) // an equivalent Rust `*mut dyn Trait`
510+
//
511+
// SO THEN WE CAN USE THE ABOVE CODE.
512+
let virtual_drop = Instance {
513+
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
514+
substs: drop_fn.substs,
515+
};
516+
debug!("ty = {:?}", ty);
517+
debug!("drop_fn = {:?}", drop_fn);
518+
debug!("args = {:?}", args);
519+
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
520+
let meta_ptr = place.project_field(bx, 1);
521+
let meta = bx.load_operand(meta_ptr);
522+
// Truncate vtable off of args list
523+
args = &args[..1];
524+
debug!("args' = {:?}", args);
525+
(
526+
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
527+
.get_fn(bx, meta.immediate(), ty, &fn_abi),
528+
fn_abi,
529+
)
530+
}
531+
_ => (bx.get_fn_addr(drop_fn), bx.fn_abi_of_instance(drop_fn, ty::List::empty())),
532+
};
535533
helper.do_call(
536534
self,
537535
bx,

compiler/rustc_middle/src/ty/layout.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -770,7 +770,7 @@ where
770770

771771
ty::Dynamic(_, _, ty::DynStar) => {
772772
if i == 0 {
773-
TyMaybeWithLayout::Ty(tcx.types.usize)
773+
TyMaybeWithLayout::Ty(tcx.mk_mut_ptr(tcx.types.unit))
774774
} else if i == 1 {
775775
// FIXME(dyn-star) same FIXME as above applies here too
776776
TyMaybeWithLayout::Ty(

compiler/rustc_ty_utils/src/layout.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -193,7 +193,7 @@ fn layout_of_uncached<'tcx>(
193193
}
194194

195195
ty::Dynamic(_, _, ty::DynStar) => {
196-
let mut data = scalar_unit(Int(dl.ptr_sized_integer(), false));
196+
let mut data = scalar_unit(Pointer(AddressSpace::DATA));
197197
data.valid_range_mut().start = 0;
198198
let mut vtable = scalar_unit(Pointer(AddressSpace::DATA));
199199
vtable.valid_range_mut().start = 1;

compiler/rustc_type_ir/src/sty.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -26,11 +26,9 @@ pub enum DynKind {
2626
Dyn,
2727
/// A sized `dyn* Trait` object
2828
///
29-
/// These objects are represented as a `(data, vtable)` pair where `data` is a ptr-sized value
30-
/// (often a pointer to the real object, but not necessarily) and `vtable` is a pointer to
31-
/// the vtable for `dyn* Trait`. The representation is essentially the same as `&dyn Trait`
32-
/// or similar, but the drop function included in the vtable is responsible for freeing the
33-
/// underlying storage if needed. This allows a `dyn*` object to be treated agnostically with
29+
/// These objects are represented as a `(data, vtable)` pair where `data` is a value of some
30+
/// ptr-sized and ptr-aligned dynamically determined type `T` and `vtable` is a pointer to the
31+
/// vtable of `impl T for Trait`. This allows a `dyn*` object to be treated agnostically with
3432
/// respect to whether it points to a `Box<T>`, `Rc<T>`, etc.
3533
DynStar,
3634
}

tests/codegen/function-arguments.rs

+9
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
// compile-flags: -O -C no-prepopulate-passes
22

33
#![crate_type = "lib"]
4+
#![feature(dyn_star)]
45

56
use std::mem::MaybeUninit;
67
use std::num::NonZeroU64;
@@ -279,3 +280,11 @@ pub fn enum_id_1(x: Option<Result<u16, u16>>) -> Option<Result<u16, u16>> {
279280
pub fn enum_id_2(x: Option<u8>) -> Option<u8> {
280281
x
281282
}
283+
284+
// CHECK: { {{\{\}\*|ptr}}, {{.+}} } @dyn_star({{\{\}\*|ptr}} noundef %x.0, {{.+}} noalias noundef readonly align {{.*}} dereferenceable({{.*}}) %x.1)
285+
// Expect an ABI something like `{ {}*, [3 x i64]* }`, but that's hard to match on generically,
286+
// so do like the `trait_box` test and just match on `{{.+}}` for the vtable.
287+
#[no_mangle]
288+
pub fn dyn_star(x: dyn* Drop) -> dyn* Drop {
289+
x
290+
}
+23
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,23 @@
1+
// run-pass
2+
// compile-flags: -Copt-level=0 -Cllvm-args=-opaque-pointers=0
3+
4+
// (opaque-pointers flag is called force-opaque-pointers in LLVM 13...)
5+
// min-llvm-version: 14.0
6+
7+
// This test can be removed once non-opaque pointers are gone from LLVM, maybe.
8+
9+
#![feature(dyn_star, pointer_like_trait)]
10+
#![allow(incomplete_features)]
11+
12+
use std::fmt::Debug;
13+
use std::marker::PointerLike;
14+
15+
fn make_dyn_star<'a>(t: impl PointerLike + Debug + 'a) -> dyn* Debug + 'a {
16+
t as _
17+
}
18+
19+
fn main() {
20+
println!("{:?}", make_dyn_star(Box::new(1i32)));
21+
println!("{:?}", make_dyn_star(2usize));
22+
println!("{:?}", make_dyn_star((3usize,)));
23+
}

0 commit comments

Comments
 (0)