Skip to content

Commit

Permalink
dyn* through more typechecking and MIR
Browse files Browse the repository at this point in the history
  • Loading branch information
eholk committed Sep 12, 2022
1 parent 7fccac3 commit 549c105
Show file tree
Hide file tree
Showing 15 changed files with 168 additions and 13 deletions.
37 changes: 35 additions & 2 deletions compiler/rustc_borrowck/src/type_check/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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};
Expand Down Expand Up @@ -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,
Expand Down
46 changes: 44 additions & 2 deletions compiler/rustc_codegen_ssa/src/mir/block.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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>,
Expand Down Expand Up @@ -397,20 +398,61 @@ 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)
.get_fn(&mut bx, vtable, ty, &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())),
};
helper.do_call(
Expand Down
10 changes: 10 additions & 0 deletions compiler/rustc_codegen_ssa/src/mir/rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
)
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_const_eval/src/interpret/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(())
}
Expand Down
4 changes: 4 additions & 0 deletions compiler/rustc_const_eval/src/transform/check_consts/check.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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, _) => {}
Expand Down
3 changes: 3 additions & 0 deletions compiler/rustc_const_eval/src/transform/validate.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down
1 change: 1 addition & 0 deletions compiler/rustc_middle/src/mir/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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(_)
Expand Down
2 changes: 2 additions & 0 deletions compiler/rustc_middle/src/mir/syntax.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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,
}
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_middle/src/ty/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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)]
Expand Down Expand Up @@ -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)
Expand All @@ -50,6 +53,7 @@ pub enum CastKind {
ArrayPtrCast,
FnPtrPtrCast,
FnPtrAddrCast,
DynStarCast,
}

impl<'tcx> CastTy<'tcx> {
Expand All @@ -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,
}
}
Expand Down
26 changes: 24 additions & 2 deletions compiler/rustc_middle/src/ty/layout.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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;
Expand Down Expand Up @@ -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() {
Expand Down Expand Up @@ -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,
&[],
Expand Down Expand Up @@ -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, .. }) => {
Expand Down Expand Up @@ -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(..)
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_middle/src/ty/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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> {
Expand Down
5 changes: 5 additions & 0 deletions compiler/rustc_mir_build/src/build/expr/as_rvalue.rs
Original file line number Diff line number Diff line change
Expand Up @@ -216,13 +216,18 @@ 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
}
(Some(CastTy::Int(_)), Some(CastTy::Ptr(_))) => {
CastKind::PointerFromExposedAddress
}
(_, Some(CastTy::DynStar)) => CastKind::DynStar,
(_, _) => CastKind::Misc,
};
block.and(Rvalue::Cast(cast_kind, source, expr.ty))
Expand Down
6 changes: 6 additions & 0 deletions compiler/rustc_typeck/src/check/cast.rs
Original file line number Diff line number Diff line change
Expand Up @@ -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),
}
}

Expand Down
14 changes: 14 additions & 0 deletions src/test/ui/async-await/dyn-star-trait-const.rs
Original file line number Diff line number Diff line change
@@ -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();
}
12 changes: 5 additions & 7 deletions src/test/ui/dyn-star/make-dyn-star.rs
Original file line number Diff line number Diff line change
@@ -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);
}

0 comments on commit 549c105

Please sign in to comment.