From 549c105bb365e14cb132b29a94126715158c5cfa Mon Sep 17 00:00:00 2001 From: Eric Holk Date: Tue, 28 Jun 2022 14:02:30 -0700 Subject: [PATCH] dyn* through more typechecking and MIR --- compiler/rustc_borrowck/src/type_check/mod.rs | 37 ++++++++++++++- compiler/rustc_codegen_ssa/src/mir/block.rs | 46 ++++++++++++++++++- compiler/rustc_codegen_ssa/src/mir/rvalue.rs | 10 ++++ .../rustc_const_eval/src/interpret/cast.rs | 4 ++ .../src/transform/check_consts/check.rs | 4 ++ .../src/transform/validate.rs | 3 ++ compiler/rustc_middle/src/mir/mod.rs | 1 + compiler/rustc_middle/src/mir/syntax.rs | 2 + compiler/rustc_middle/src/ty/cast.rs | 5 ++ compiler/rustc_middle/src/ty/layout.rs | 26 ++++++++++- compiler/rustc_middle/src/ty/mod.rs | 6 +++ .../src/build/expr/as_rvalue.rs | 5 ++ compiler/rustc_typeck/src/check/cast.rs | 6 +++ .../ui/async-await/dyn-star-trait-const.rs | 14 ++++++ src/test/ui/dyn-star/make-dyn-star.rs | 12 ++--- 15 files changed, 168 insertions(+), 13 deletions(-) create mode 100644 src/test/ui/async-await/dyn-star-trait-const.rs diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index fc0e95f30c98f..c78f9282e307a 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -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, diff --git a/compiler/rustc_codegen_ssa/src/mir/block.rs b/compiler/rustc_codegen_ssa/src/mir/block.rs index 3154f12a77964..fb75ecc17356b 100644 --- a/compiler/rustc_codegen_ssa/src/mir/block.rs +++ b/compiler/rustc_codegen_ssa/src/mir/block.rs @@ -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 ( *mut T, Vtable ) + // 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, Vtable) + // + // 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( diff --git a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs index 574746e340b7b..d3c6b731de334 100644 --- a/compiler/rustc_codegen_ssa/src/mir/rvalue.rs +++ b/compiler/rustc_codegen_ssa/src/mir/rvalue.rs @@ -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, ) diff --git a/compiler/rustc_const_eval/src/interpret/cast.rs b/compiler/rustc_const_eval/src/interpret/cast.rs index 3af48c3ed1a15..9beeb2d8b2c7e 100644 --- a/compiler/rustc_const_eval/src/interpret/cast.rs +++ b/compiler/rustc_const_eval/src/interpret/cast.rs @@ -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(()) } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/check.rs b/compiler/rustc_const_eval/src/transform/check_consts/check.rs index 3fa40dc305952..7e15858c8c188 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/check.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/check.rs @@ -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, _) => {} diff --git a/compiler/rustc_const_eval/src/transform/validate.rs b/compiler/rustc_const_eval/src/transform/validate.rs index 8576e0f0f7c16..1c4c7e7079d64 100644 --- a/compiler/rustc_const_eval/src/transform/validate.rs +++ b/compiler/rustc_const_eval/src/transform/validate.rs @@ -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 diff --git a/compiler/rustc_middle/src/mir/mod.rs b/compiler/rustc_middle/src/mir/mod.rs index dd768c5358d5a..47e62e82ac4aa 100644 --- a/compiler/rustc_middle/src/mir/mod.rs +++ b/compiler/rustc_middle/src/mir/mod.rs @@ -1834,6 +1834,7 @@ impl<'tcx> Rvalue<'tcx> { // While the model is undecided, we should be conservative. See // Rvalue::Cast(CastKind::PointerExposeAddress, _, _) => false, + Rvalue::Cast(CastKind::DynStar, _, _) => false, Rvalue::Use(_) | Rvalue::CopyForDeref(_) diff --git a/compiler/rustc_middle/src/mir/syntax.rs b/compiler/rustc_middle/src/mir/syntax.rs index 1f7643a76afe5..d2bb897b5b676 100644 --- a/compiler/rustc_middle/src/mir/syntax.rs +++ b/compiler/rustc_middle/src/mir/syntax.rs @@ -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, } diff --git a/compiler/rustc_middle/src/ty/cast.rs b/compiler/rustc_middle/src/ty/cast.rs index c4b743dd46701..cc5381b467d78 100644 --- a/compiler/rustc_middle/src/ty/cast.rs +++ b/compiler/rustc_middle/src/ty/cast.rs @@ -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, } } diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index b9b46518fa23b..2e68b96f87bc6 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -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(..) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index df72260597f9f..b4418ef9aa0f6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -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> { diff --git a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs index c1282b8ddaff4..f9394564f0eb1 100644 --- a/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs +++ b/compiler/rustc_mir_build/src/build/expr/as_rvalue.rs @@ -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)) diff --git a/compiler/rustc_typeck/src/check/cast.rs b/compiler/rustc_typeck/src/check/cast.rs index fa6224f1915a9..1248d5c8426ae 100644 --- a/compiler/rustc_typeck/src/check/cast.rs +++ b/compiler/rustc_typeck/src/check/cast.rs @@ -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), } } diff --git a/src/test/ui/async-await/dyn-star-trait-const.rs b/src/test/ui/async-await/dyn-star-trait-const.rs new file mode 100644 index 0000000000000..c4861de3606c7 --- /dev/null +++ b/src/test/ui/async-await/dyn-star-trait-const.rs @@ -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(); +} diff --git a/src/test/ui/dyn-star/make-dyn-star.rs b/src/test/ui/dyn-star/make-dyn-star.rs index 17356bfbd84b9..593a4509f7d53 100644 --- a/src/test/ui/dyn-star/make-dyn-star.rs +++ b/src/test/ui/dyn-star/make-dyn-star.rs @@ -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); +}