diff options
| author | bors <bors@rust-lang.org> | 2022-10-15 07:36:38 +0000 |
|---|---|---|
| committer | bors <bors@rust-lang.org> | 2022-10-15 07:36:38 +0000 |
| commit | b15e2c129e732fb3f1ff3c707d76341047a66af0 (patch) | |
| tree | 77f9ce52d2d1403fe53d10ef79864c6a95fb48e9 /compiler/rustc_codegen_ssa/src | |
| parent | 46244f335b5262ef9bdc34cc564b4dea221948f6 (diff) | |
| parent | 8c7e836abb62331ebb8350c7724c95241ef95a51 (diff) | |
| download | rust-b15e2c129e732fb3f1ff3c707d76341047a66af0.tar.gz rust-b15e2c129e732fb3f1ff3c707d76341047a66af0.zip | |
Auto merge of #101832 - compiler-errors:dyn-star-plus, r=eholk
Make `dyn*` casts into a coercion, allow `dyn*` upcasting I know that `dyn*` is likely not going to be a feature exposed to surface Rust, but this makes it slightly more ergonomic to write tests for these types anyways. ... and this was just fun to implement anyways. 1. Make `dyn*` into a coercion instead of a cast 2. Enable `dyn*` upcasting since we basically get it for free 3. Simplify some of the cast checking code since we're using the coercion path now r? `@eholk` but feel free to reassign cc `@nikomatsakis` and `@tmandry` who might care about making `dyn*` casts into a coercion
Diffstat (limited to 'compiler/rustc_codegen_ssa/src')
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/base.rs | 64 | ||||
| -rw-r--r-- | compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 27 |
2 files changed, 57 insertions, 34 deletions
diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index cb5436fd61a..0ca6408aab9 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -38,7 +38,7 @@ use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::Symbol; use rustc_span::{DebuggerVisualizerFile, DebuggerVisualizerType}; -use rustc_target::abi::{Align, VariantIdx}; +use rustc_target::abi::{Align, Size, VariantIdx}; use std::collections::BTreeSet; use std::convert::TryFrom; @@ -150,7 +150,12 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( (&ty::Array(_, len), &ty::Slice(_)) => { cx.const_usize(len.eval_usize(cx.tcx(), ty::ParamEnv::reveal_all())) } - (&ty::Dynamic(ref data_a, ..), &ty::Dynamic(ref data_b, ..)) => { + ( + &ty::Dynamic(ref data_a, _, src_dyn_kind), + &ty::Dynamic(ref data_b, _, target_dyn_kind), + ) => { + assert_eq!(src_dyn_kind, target_dyn_kind); + let old_info = old_info.expect("unsized_info: missing old info for trait upcasting coercion"); if data_a.principal_def_id() == data_b.principal_def_id() { @@ -166,11 +171,7 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( if let Some(entry_idx) = vptr_entry_idx { let ptr_ty = cx.type_i8p(); let ptr_align = cx.tcx().data_layout.pointer_align.abi; - let vtable_ptr_ty = cx.scalar_pair_element_backend_type( - cx.layout_of(cx.tcx().mk_mut_ptr(target)), - 1, - true, - ); + let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind); let llvtable = bx.pointercast(old_info, bx.type_ptr_to(ptr_ty)); let gep = bx.inbounds_gep( ptr_ty, @@ -186,18 +187,32 @@ pub fn unsized_info<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( old_info } } - (_, &ty::Dynamic(ref data, ..)) => { - let vtable_ptr_ty = cx.scalar_pair_element_backend_type( - cx.layout_of(cx.tcx().mk_mut_ptr(target)), - 1, - true, - ); + (_, &ty::Dynamic(ref data, _, target_dyn_kind)) => { + let vtable_ptr_ty = vtable_ptr_ty(cx, target, target_dyn_kind); cx.const_ptrcast(meth::get_vtable(cx, source, data.principal()), vtable_ptr_ty) } _ => bug!("unsized_info: invalid unsizing {:?} -> {:?}", source, target), } } +// Returns the vtable pointer type of a `dyn` or `dyn*` type +fn vtable_ptr_ty<'tcx, Cx: CodegenMethods<'tcx>>( + cx: &Cx, + target: Ty<'tcx>, + kind: ty::DynKind, +) -> <Cx as BackendTypes>::Type { + cx.scalar_pair_element_backend_type( + cx.layout_of(match kind { + // vtable is the second field of `*mut dyn Trait` + ty::Dyn => cx.tcx().mk_mut_ptr(target), + // vtable is the second field of `dyn* Trait` + ty::DynStar => target, + }), + 1, + true, + ) +} + /// Coerces `src` to `dst_ty`. `src_ty` must be a pointer. pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( bx: &mut Bx, @@ -247,6 +262,29 @@ pub fn unsize_ptr<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( } } +/// Coerces `src` to `dst_ty` which is guaranteed to be a `dyn*` type. +pub fn cast_to_dyn_star<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( + bx: &mut Bx, + src: Bx::Value, + src_ty_and_layout: TyAndLayout<'tcx>, + dst_ty: Ty<'tcx>, + old_info: Option<Bx::Value>, +) -> (Bx::Value, Bx::Value) { + debug!("cast_to_dyn_star: {:?} => {:?}", src_ty_and_layout.ty, dst_ty); + assert!( + matches!(dst_ty.kind(), ty::Dynamic(_, _, ty::DynStar)), + "destination type must be a dyn*" + ); + // FIXME(dyn-star): this is probably not the best way to check if this is + // a pointer, and really we should ensure that the value is a suitable + // pointer earlier in the compilation process. + let src = match src_ty_and_layout.pointee_info_at(bx.cx(), Size::ZERO) { + Some(_) => bx.ptrtoint(src, bx.cx().type_isize()), + None => bx.bitcast(src, bx.type_isize()), + }; + (src, unsized_info(bx, src_ty_and_layout.ty, dst_ty, old_info)) +} + /// Coerces `src`, which is a reference to a value of type `src_ty`, /// to a value of type `dst_ty`, and stores the result in `dst`. pub fn coerce_unsized_into<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>>( diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 4ed99df1e81..4aab31fbfe7 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -4,7 +4,6 @@ use super::{FunctionCx, LocalRef}; use crate::base; use crate::common::{self, IntPredicate}; -use crate::meth::get_vtable; use crate::traits::*; use crate::MemFlags; @@ -14,7 +13,6 @@ use rustc_middle::ty::cast::{CastTy, IntTy}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::{self, adjustment::PointerCast, Instance, Ty, TyCtxt}; use rustc_span::source_map::{Span, DUMMY_SP}; -use rustc_target::abi::Size; impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { #[instrument(level = "trace", skip(self, bx))] @@ -274,27 +272,14 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> { } } mir::CastKind::DynStar => { - let data = match operand.val { + let (lldata, llextra) = match operand.val { OperandValue::Ref(_, _, _) => todo!(), - OperandValue::Immediate(v) => v, - OperandValue::Pair(_, _) => todo!(), - }; - let trait_ref = - if let ty::Dynamic(data, _, ty::DynStar) = cast.ty.kind() { - data.principal() - } else { - bug!("Only valid to do a DynStar cast into a DynStar type") - }; - let vtable = get_vtable(bx.cx(), source.ty(self.mir, bx.tcx()), trait_ref); - let vtable = bx.pointercast(vtable, bx.cx().type_ptr_to(bx.cx().type_isize())); - // FIXME(dyn-star): this is probably not the best way to check if this is - // a pointer, and really we should ensure that the value is a suitable - // pointer earlier in the compilation process. - let data = match operand.layout.pointee_info_at(bx.cx(), Size::ZERO) { - Some(_) => bx.ptrtoint(data, bx.cx().type_isize()), - None => data, + OperandValue::Immediate(v) => (v, None), + OperandValue::Pair(v, l) => (v, Some(l)), }; - OperandValue::Pair(data, vtable) + let (lldata, llextra) = + base::cast_to_dyn_star(&mut bx, lldata, operand.layout, cast.ty, llextra); + OperandValue::Pair(lldata, llextra) } mir::CastKind::Pointer( PointerCast::MutToConstPointer | PointerCast::ArrayToPointer, |
