dyn* through more typechecking and MIR
This commit is contained in:
parent
7fccac3ea0
commit
549c105bb3
15 changed files with 168 additions and 13 deletions
|
@ -30,8 +30,9 @@ use rustc_middle::ty::cast::CastTy;
|
|||
use rustc_middle::ty::subst::{GenericArgKind, SubstsRef, UserSubsts};
|
||||
use rustc_middle::ty::visit::TypeVisitable;
|
||||
use rustc_middle::ty::{
|
||||
self, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, OpaqueHiddenType,
|
||||
OpaqueTypeKey, RegionVid, ToPredicate, Ty, TyCtxt, UserType, UserTypeAnnotationIndex,
|
||||
self, Binder, CanonicalUserTypeAnnotation, CanonicalUserTypeAnnotations, Dynamic,
|
||||
OpaqueHiddenType, OpaqueTypeKey, RegionVid, ToPredicate, TraitObjectRepresentation, Ty, TyCtxt,
|
||||
UserType, UserTypeAnnotationIndex,
|
||||
};
|
||||
use rustc_span::def_id::CRATE_DEF_ID;
|
||||
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) => {
|
||||
let ty::RawPtr(ty::TypeAndMut {
|
||||
ty: ty_from,
|
||||
|
|
|
@ -16,7 +16,7 @@ use rustc_index::vec::Idx;
|
|||
use rustc_middle::mir::{self, AssertKind, SwitchTargets};
|
||||
use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf};
|
||||
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::{sym, Symbol};
|
||||
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);
|
||||
}
|
||||
|
||||
#[tracing::instrument(level = "debug", skip(self, helper, bx))]
|
||||
fn codegen_drop_terminator(
|
||||
&mut self,
|
||||
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() {
|
||||
// FIXME(eddyb) perhaps move some of this logic into
|
||||
// `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 {
|
||||
def: ty::InstanceDef::Virtual(drop_fn.def_id(), 0),
|
||||
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 vtable = args[1];
|
||||
// Truncate vtable off of args list
|
||||
args = &args[..1];
|
||||
(
|
||||
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,
|
||||
)
|
||||
}
|
||||
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())),
|
||||
};
|
||||
helper.do_call(
|
||||
|
|
|
@ -271,6 +271,16 @@ impl<'a, 'tcx, Bx: BuilderMethods<'a, 'tcx>> FunctionCx<'a, 'tcx, Bx> {
|
|||
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(
|
||||
PointerCast::MutToConstPointer | PointerCast::ArrayToPointer,
|
||||
)
|
||||
|
|
|
@ -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),
|
||||
}
|
||||
}
|
||||
|
||||
DynStar => {
|
||||
unimplemented!()
|
||||
}
|
||||
}
|
||||
Ok(())
|
||||
}
|
||||
|
|
|
@ -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.
|
||||
}
|
||||
|
||||
Rvalue::Cast(CastKind::DynStar, _, _) => {
|
||||
unimplemented!()
|
||||
}
|
||||
|
||||
Rvalue::Cast(CastKind::Misc, _, _) => {}
|
||||
|
||||
Rvalue::NullaryOp(NullOp::SizeOf | NullOp::AlignOf, _) => {}
|
||||
|
|
|
@ -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
|
||||
CastKind::PointerFromExposedAddress
|
||||
| CastKind::PointerExposeAddress
|
||||
|
|
|
@ -1834,6 +1834,7 @@ impl<'tcx> Rvalue<'tcx> {
|
|||
// While the model is undecided, we should be conservative. See
|
||||
// <https://www.ralfj.de/blog/2022/04/11/provenance-exposed.html>
|
||||
Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false,
|
||||
Rvalue::Cast(CastKind::DynStar, _, _) => false,
|
||||
|
||||
Rvalue::Use(_)
|
||||
| Rvalue::CopyForDeref(_)
|
||||
|
|
|
@ -1139,6 +1139,8 @@ pub enum CastKind {
|
|||
/// 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.
|
||||
Pointer(PointerCast),
|
||||
/// Cast into a dyn* object.
|
||||
DynStar,
|
||||
/// Remaining unclassified casts.
|
||||
Misc,
|
||||
}
|
||||
|
|
|
@ -4,6 +4,7 @@
|
|||
use crate::ty::{self, Ty};
|
||||
|
||||
use rustc_macros::HashStable;
|
||||
use rustc_type_ir::TraitObjectRepresentation;
|
||||
|
||||
/// Types that are represented as ints.
|
||||
#[derive(Copy, Clone, Debug, PartialEq, Eq)]
|
||||
|
@ -33,6 +34,8 @@ pub enum CastTy<'tcx> {
|
|||
FnPtr,
|
||||
/// Raw pointers.
|
||||
Ptr(ty::TypeAndMut<'tcx>),
|
||||
/// Casting into a `dyn*` value.
|
||||
DynStar,
|
||||
}
|
||||
|
||||
/// Cast Kind. See [RFC 401](https://rust-lang.github.io/rfcs/0401-coercions.html)
|
||||
|
@ -50,6 +53,7 @@ pub enum CastKind {
|
|||
ArrayPtrCast,
|
||||
FnPtrPtrCast,
|
||||
FnPtrAddrCast,
|
||||
DynStarCast,
|
||||
}
|
||||
|
||||
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::RawPtr(mt) => Some(CastTy::Ptr(mt)),
|
||||
ty::FnPtr(..) => Some(CastTy::FnPtr),
|
||||
ty::Dynamic(_, _, TraitObjectRepresentation::Sized) => Some(CastTy::DynStar),
|
||||
_ => None,
|
||||
}
|
||||
}
|
||||
|
|
|
@ -21,6 +21,7 @@ use rustc_target::abi::call::{
|
|||
};
|
||||
use rustc_target::abi::*;
|
||||
use rustc_target::spec::{abi::Abi as SpecAbi, HasTargetSpec, PanicStrategy, Target};
|
||||
use rustc_type_ir::TraitObjectRepresentation;
|
||||
|
||||
use std::cmp::{self, Ordering};
|
||||
use std::fmt;
|
||||
|
@ -625,6 +626,14 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
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.
|
||||
ty::Array(element, mut count) => {
|
||||
if count.has_projections() {
|
||||
|
@ -679,7 +688,7 @@ impl<'tcx> LayoutCx<'tcx, TyCtxt<'tcx>> {
|
|||
|
||||
// Odd unit types.
|
||||
ty::FnDef(..) => univariant(&[], &ReprOptions::default(), StructKind::AlwaysSized)?,
|
||||
ty::Dynamic(..) | ty::Foreign(..) => {
|
||||
ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) | ty::Foreign(..) => {
|
||||
let mut unit = self.univariant_uninterned(
|
||||
ty,
|
||||
&[],
|
||||
|
@ -2435,7 +2444,9 @@ where
|
|||
| ty::FnDef(..)
|
||||
| ty::GeneratorWitness(..)
|
||||
| ty::Foreign(..)
|
||||
| ty::Dynamic(..) => bug!("TyAndLayout::field({:?}): not applicable", this),
|
||||
| ty::Dynamic(_, _, TraitObjectRepresentation::Unsized) => {
|
||||
bug!("TyAndLayout::field({:?}): not applicable", this)
|
||||
}
|
||||
|
||||
// Potentially-fat pointers.
|
||||
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::Bound(..)
|
||||
| ty::Placeholder(..)
|
||||
|
|
|
@ -1113,6 +1113,12 @@ pub trait ToPredicate<'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>> {
|
||||
#[inline(always)]
|
||||
fn to_predicate(self, tcx: TyCtxt<'tcx>) -> Predicate<'tcx> {
|
||||
|
|
|
@ -216,6 +216,10 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
};
|
||||
let from_ty = CastTy::from_ty(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) {
|
||||
(Some(CastTy::Ptr(_) | CastTy::FnPtr), Some(CastTy::Int(_))) => {
|
||||
CastKind::PointerExposeAddress
|
||||
|
@ -223,6 +227,7 @@ impl<'a, 'tcx> Builder<'a, 'tcx> {
|
|||
(Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => {
|
||||
CastKind::PointerFromExposedAddress
|
||||
}
|
||||
(_, Some(CastTy::DynStar)) => CastKind::DynStar,
|
||||
(_, _) => CastKind::Misc,
|
||||
};
|
||||
block.and(Rvalue::Cast(cast_kind, source, expr.ty))
|
||||
|
|
|
@ -928,6 +928,12 @@ impl<'a, 'tcx> CastCheck<'tcx> {
|
|||
(Int(Char) | Int(Bool), Int(_)) => Ok(CastKind::PrimIntCast),
|
||||
|
||||
(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),
|
||||
}
|
||||
}
|
||||
|
||||
|
|
14
src/test/ui/async-await/dyn-star-trait-const.rs
Normal file
14
src/test/ui/async-await/dyn-star-trait-const.rs
Normal 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();
|
||||
}
|
|
@ -1,14 +1,12 @@
|
|||
// check-pass
|
||||
// run-pass
|
||||
#![feature(dyn_star)]
|
||||
|
||||
use std::fmt::Debug;
|
||||
|
||||
pub fn dyn_star_parameter(_: dyn* Send) {
|
||||
}
|
||||
|
||||
fn make_dyn_star() {
|
||||
let i = 42usize;
|
||||
fn make_dyn_star(i: usize) {
|
||||
let dyn_i: dyn* Debug = i as dyn* Debug;
|
||||
}
|
||||
|
||||
fn main() {}
|
||||
fn main() {
|
||||
make_dyn_star(42);
|
||||
}
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue