1
Fork 0

dyn* through more typechecking and MIR

This commit is contained in:
Eric Holk 2022-06-28 14:02:30 -07:00
parent 7fccac3ea0
commit 549c105bb3
15 changed files with 168 additions and 13 deletions

View file

@ -30,8 +30,9 @@ use rustc_middle::ty::cast::CastTy;
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts}; use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::visit::TypeVisitable;
use rustc_middle::ty::{ use rustc_middle::ty::{
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType, self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic,
OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex, OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, TraitObjectRepresentation, Ty, TyCtxt,
UserType, UserTypeAnnotationIndex,
}; };
use rustc_span::def_id::CRATE_DEF_ID; use rustc_span::def_id::CRATE_DEF_ID;
use rustc_span::{Span, DUMMY_SP}; use rustc_span::{Span, DUMMY_SP};
@ -2009,6 +2010,38 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> {
); );
} }
CastKind::DynStar => {
// get the constraints from the target type (`dyn* Clone`)
//
// apply them to prove that the source type `Foo` implements `Clone` etc
let (existential_predicates, region) = match ty.kind() {
Dynamic(predicates, region, TraitObjectRepresentation::Sized) => {
(predicates, region)
}
_ => panic!("Invalid dyn* cast_ty"),
};
let self_ty = op.ty(body, tcx);
self.prove_predicates(
existential_predicates
.iter()
.map(|predicate| predicate.with_self_ty(tcx, self_ty)),
location.to_locations(),
ConstraintCategory::Cast,
);
let outlives_predicate =
tcx.mk_predicate(Binder::dummy(ty::PredicateKind::TypeOutlives(
ty::OutlivesPredicate(self_ty, *region),
)));
self.prove_predicate(
outlives_predicate,
location.to_locations(),
ConstraintCategory::Cast,
);
}
CastKind::Pointer(PointerCast::MutToConstPointer) => { CastKind::Pointer(PointerCast::MutToConstPointer) => {
let ty::RawPtr(ty::TypeAndMut { let ty::RawPtr(ty::TypeAndMut {
ty: ty_from, ty: ty_from,

View file

@ -16,7 +16,7 @@ use rustc_index::vec::Idx;
use rustc_middle::mir::{self, AssertKind, SwitchTargets}; use rustc_middle::mir::{self, AssertKind, SwitchTargets};
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf}; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths}; use rustc_middle::ty::print::{with_no_trimmed_paths, with_no_visible_paths};
use rustc_middle::ty::{self, Instance, Ty, TypeVisitable}; use rustc_middle::ty::{self, Instance, Ty, TypeVisitable, TraitObjectRepresentation};
use rustc_span::source_map::Span; use rustc_span::source_map::Span;
use rustc_span::{sym, Symbol}; use rustc_span::{sym, Symbol};
use rustc_symbol_mangling::typeid::typeid_for_fnabi; use rustc_symbol_mangling::typeid::typeid_for_fnabi;
@ -367,6 +367,7 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bx.ret(llval); bx.ret(llval);
} }
#[tracing::instrument(level = "debug", skip(self, helper, bx))]
fn codegen_drop_terminator( fn codegen_drop_terminator(
&mut self, &mut self,
helper: TerminatorCodegenHelper<'tcx>, helper: TerminatorCodegenHelper<'tcx>,
@ -397,13 +398,29 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
let (drop_fn, fn_abi) = match ty.kind() { let (drop_fn, fn_abi) = match ty.kind() {
// FIXME(eddyb) perhaps move some of this logic into // FIXME(eddyb) perhaps move some of this logic into
// `Instance::resolve_drop_in_place`? // `Instance::resolve_drop_in_place`?
ty::Dynamic(..) => { ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) => {
// IN THIS ARM, WE HAVE:
// ty = *mut (dyn Trait)
// which is: exists<T> ( *mut T, Vtable<T: Trait> )
// args[0] args[1]
//
// args = ( Data, Vtable )
// |
// v
// /-------\
// | ... |
// \-------/
//
let virtual_drop = Instance { let virtual_drop = Instance {
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0), def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
substs: drop_fn.substs, substs: drop_fn.substs,
}; };
debug!("ty = {:?}", ty);
debug!("drop_fn = {:?}", drop_fn);
debug!("args = {:?}", args);
let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty()); let fn_abi = bx.fn_abi_of_instance(virtual_drop, ty::List::empty());
let vtable = args[1]; let vtable = args[1];
// Truncate vtable off of args list
args = &args[..1]; args = &args[..1];
( (
meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE) meth::VirtualIndex::from_index(ty::COMMON_VTABLE_ENTRIES_DROPINPLACE)
@ -411,6 +428,31 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
fn_abi, fn_abi,
) )
} }
ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => {
// IN THIS ARM, WE HAVE:
// ty = *mut (dyn* Trait)
// which is: *mut exists<T: sizeof(T) == sizeof(usize)> (T, Vtable<T: Trait>)
//
// args = [ * ]
// |
// v
// ( Data, Vtable )
// |
// v
// /-------\
// | ... |
// \-------/
//
//
// 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, vtable) // an equivalent Rust `*mut dyn Trait`
//
// SO THEN WE CAN USE THE ABOVE CODE.
todo!()
}
_ => (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(

View file

@ -271,6 +271,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
bug!("unexpected non-pair operand"); bug!("unexpected non-pair operand");
} }
} }
#[allow(unreachable_code, unused)] // FIXME: remove this
mir::CastKind::DynStar => {
let data = match operand.val {
OperandValue::Ref(_, _, _) => todo!(),
OperandValue::Immediate(_) => todo!(),
OperandValue::Pair(_, _) => todo!(),
};
let vtable = todo!();
OperandValue::Pair(data, vtable)
}
mir::CastKind::Pointer( mir::CastKind::Pointer(
PointerCast::MutToConstPointer | PointerCast::ArrayToPointer, PointerCast::MutToConstPointer | PointerCast::ArrayToPointer,
) )

View file

@ -108,6 +108,10 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> {
_ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty), _ => span_bug!(self.cur_span(), "closure fn pointer on {:?}", src.layout.ty),
} }
} }
DynStar => {
unimplemented!()
}
} }
Ok(()) Ok(())
} }

View file

@ -546,6 +546,10 @@ impl<'tcx> Visitor<'tcx> for Checker<'_, 'tcx> {
// Since no pointer can ever get exposed (rejected above), this is easy to support. // Since no pointer can ever get exposed (rejected above), this is easy to support.
} }
Rvalue::Cast(CastKind::DynStar, _, _) => {
unimplemented!()
}
Rvalue::Cast(CastKind::Misc, _, _) => {} Rvalue::Cast(CastKind::Misc, _, _) => {}
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {} Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}

View file

@ -569,6 +569,9 @@ impl<'a, 'tcx> Visitor<'tcx> for TypeChecker<'a, 'tcx> {
); );
} }
} }
CastKind::DynStar => {
// FIXME: make sure nothing needs to be done here.
}
// Nothing to check here // Nothing to check here
CastKind::PointerFromExposedAddress CastKind::PointerFromExposedAddress
| CastKind::PointerExposeAddress | CastKind::PointerExposeAddress

View file

@ -1834,6 +1834,7 @@ impl<'tcx> Rvalue<'tcx> {
// While the model is undecided, we should be conservative. See // While the model is undecided, we should be conservative. See
// <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html> // <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false, Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
Rvalue::Cast(CastKind::DynStar, _, _) => false,
Rvalue::Use(_) Rvalue::Use(_)
| Rvalue::CopyForDeref(_) | Rvalue::CopyForDeref(_)

View file

@ -1139,6 +1139,8 @@ pub enum CastKind {
/// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are /// All sorts of pointer-to-pointer casts. Note that reference-to-raw-ptr casts are
/// translated into `&raw mut/const *r`, i.e., they are not actually casts. /// translated into `&raw mut/const *r`, i.e., they are not actually casts.
Pointer(PointerCast), Pointer(PointerCast),
/// Cast into a dyn* object.
DynStar,
/// Remaining unclassified casts. /// Remaining unclassified casts.
Misc, Misc,
} }

View file

@ -4,6 +4,7 @@
use crate::ty::{self, Ty}; use crate::ty::{self, Ty};
use rustc_macros::HashStable; use rustc_macros::HashStable;
use rustc_type_ir::TraitObjectRepresentation;
/// Types that are represented as ints. /// Types that are represented as ints.
#[derive(Copy, Clone, Debug, PartialEq, Eq)] #[derive(Copy, Clone, Debug, PartialEq, Eq)]
@ -33,6 +34,8 @@ pub enum CastTy<'tcx> {
FnPtr, FnPtr,
/// Raw pointers. /// Raw pointers.
Ptr(ty::TypeAndMut<'tcx>), Ptr(ty::TypeAndMut<'tcx>),
/// Casting into a `dyn*` value.
DynStar,
} }
/// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html) /// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html)
@ -50,6 +53,7 @@ pub enum CastKind {
ArrayPtrCast, ArrayPtrCast,
FnPtrPtrCast, FnPtrPtrCast,
FnPtrAddrCast, FnPtrAddrCast,
DynStarCast,
} }
impl<'tcx> CastTy<'tcx> { impl<'tcx> CastTy<'tcx> {
@ -67,6 +71,7 @@ impl<'tcx> CastTy<'tcx> {
ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)), ty::Adt(d, _) if d.is_enum() && d.is_payloadfree() => Some(CastTy::Int(IntTy::CEnum)),
ty::RawPtr(mt) => Some(CastTy::Ptr(mt)), ty::RawPtr(mt) => Some(CastTy::Ptr(mt)),
ty::FnPtr(..) => Some(CastTy::FnPtr), ty::FnPtr(..) => Some(CastTy::FnPtr),
ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => Some(CastTy::DynStar),
_ => None, _ => None,
} }
} }

View file

@ -21,6 +21,7 @@ use rustc_target::abi::call::{
}; };
use rustc_target::abi::*; use rustc_target::abi::*;
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target}; use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
use rustc_type_ir::TraitObjectRepresentation;
use std::cmp::{self, Ordering}; use std::cmp::{self, Ordering};
use std::fmt; use std::fmt;
@ -625,6 +626,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
tcx.intern_layout(self.scalar_pair(data_ptr, metadata)) tcx.intern_layout(self.scalar_pair(data_ptr, metadata))
} }
ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => {
let mut pointer = scalar_unit(Pointer);
pointer.valid_range_mut().start = 1;
let mut vtable = scalar_unit(Pointer);
vtable.valid_range_mut().start = 1;
tcx.intern_layout(self.scalar_pair(pointer, vtable))
}
// Arrays and slices. // Arrays and slices.
ty::Array(element, mut count) => { ty::Array(element, mut count) => {
if count.has_projections() { if count.has_projections() {
@ -679,7 +688,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
// Odd unit types. // Odd unit types.
ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?, ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?,
ty::Dynamic(..) | ty::Foreign(..) => { ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) | ty::Foreign(..) => {
let mut unit = self.univariant_uninterned( let mut unit = self.univariant_uninterned(
ty, ty,
&[], &[],
@ -2435,7 +2444,9 @@ where
| ty::FnDef(..) | ty::FnDef(..)
| ty::GeneratorWitness(..) | ty::GeneratorWitness(..)
| ty::Foreign(..) | ty::Foreign(..)
| ty::Dynamic(..) => bug!("TyAndLayout::field({:?}): not applicable", this), | ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) => {
bug!("TyAndLayout::field({:?}): not applicable", this)
}
// Potentially-fat pointers. // Potentially-fat pointers.
ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
@ -2534,6 +2545,17 @@ where
} }
} }
// dyn*
ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => {
TyMaybeWithLayout::TyAndLayout(
tcx.layout_of(
ty::ParamEnv::reveal_all()
.and(tcx.mk_tup([tcx.types.usize, tcx.types.usize].into_iter())),
)
.unwrap(),
)
}
ty::Projection(_) ty::Projection(_)
| ty::Bound(..) | ty::Bound(..)
| ty::Placeholder(..) | ty::Placeholder(..)

View file

@ -1113,6 +1113,12 @@ pub trait ToPredicate<'tcx> {
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>; fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx>;
} }
impl<'tcx> ToPredicate<'tcx> for Predicate<'tcx> {
fn to_predicate(self, _tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
self
}
}
impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> { impl<'tcx> ToPredicate<'tcx> for Binder<'tcx, PredicateKind<'tcx>> {
#[inline(always)] #[inline(always)]
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> { fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {

View file

@ -216,6 +216,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
}; };
let from_ty = CastTy::from_ty(ty); let from_ty = CastTy::from_ty(ty);
let cast_ty = CastTy::from_ty(expr.ty); let cast_ty = CastTy::from_ty(expr.ty);
debug!(
"ExprKind::Cast from_ty={from_ty:?}, cast_ty={:?}/{cast_ty:?}",
expr.ty,
);
let cast_kind = match (from_ty, cast_ty) { let cast_kind = match (from_ty, cast_ty) {
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => { (Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
CastKind::PointerExposeAddress CastKind::PointerExposeAddress
@ -223,6 +227,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
(Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => { (Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => {
CastKind::PointerFromExposedAddress CastKind::PointerFromExposedAddress
} }
(_, Some(CastTy::DynStar)) => CastKind::DynStar,
(_, _) => CastKind::Misc, (_, _) => CastKind::Misc,
}; };
block.and(Rvalue::Cast(cast_kind, source, expr.ty)) block.and(Rvalue::Cast(cast_kind, source, expr.ty))

View file

@ -928,6 +928,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
(Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast), (Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
(Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast), (Int(_) | Float, Int(_) | Float) => Ok(CastKind::NumericCast),
// FIXME: this needs more conditions...
(_, DynStar) => Ok(CastKind::DynStarCast),
// FIXME: do we want to allow dyn* upcasting or other casts?
(DynStar, _) => Err(CastError::IllegalCast),
} }
} }

View file

@ -0,0 +1,14 @@
// run-pass
// ignore-test
#![feature(async_fn_in_traits)]
use std::fmt::Debug;
fn make_dyn_star() {
let i = 42usize;
let dyn_i: dyn* Debug = i as dyn* Debug;
}
fn main() {
make_dyn_star();
}

View file

@ -1,14 +1,12 @@
// check-pass // run-pass
#![feature(dyn_star)] #![feature(dyn_star)]
use std::fmt::Debug; use std::fmt::Debug;
pub fn dyn_star_parameter(_: dyn* Send) { fn make_dyn_star(i: usize) {
}
fn make_dyn_star() {
let i = 42usize;
let dyn_i: dyn* Debug = i as dyn* Debug; let dyn_i: dyn* Debug = i as dyn* Debug;
} }
fn main() {} fn main() {
make_dyn_star(42);
}