1
Fork 0

Be cautious of calling upvar_tys before mir

This commit is contained in:
Aman Arora 2020-11-07 01:04:27 -05:00 committed by Roxane
parent 5da2bf197d
commit e35e46c113
2 changed files with 136 additions and 110 deletions

View file

@ -2105,118 +2105,148 @@ where
} }
fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout { fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout {
let tcx = cx.tcx(); enum TyMaybeWithLayout<C: LayoutOf> {
let tag_layout = |tag: &Scalar| -> C::TyAndLayout { Ty(C::Ty),
let layout = Layout::scalar(cx, tag.clone()); TyAndLayout(C::TyAndLayout),
MaybeResult::from(Ok(TyAndLayout { }
layout: tcx.intern_layout(layout),
ty: tag.value.to_ty(tcx),
}))
};
cx.layout_of(match *this.ty.kind() { fn ty_and_layout_kind<
ty::Bool C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout: MaybeResult<TyAndLayout<'tcx>>>
| ty::Char + HasTyCtxt<'tcx>
| ty::Int(_) + HasParamEnv<'tcx>,
| ty::Uint(_) >(
| ty::Float(_) this: TyAndLayout<'tcx>,
| ty::FnPtr(_) cx: &C,
| ty::Never i: usize,
| ty::FnDef(..) ty: C::Ty,
| ty::GeneratorWitness(..) ) -> TyMaybeWithLayout<C> {
| ty::Foreign(..) let tcx = cx.tcx();
| ty::Dynamic(..) => bug!("TyAndLayout::field_type({:?}): not applicable", this), let tag_layout = |tag: &Scalar| -> C::TyAndLayout {
let layout = Layout::scalar(cx, tag.clone());
MaybeResult::from(Ok(TyAndLayout {
layout: tcx.intern_layout(layout),
ty: tag.value.to_ty(tcx),
}))
};
// Potentially-fat pointers. match *ty.kind() {
ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { ty::Bool
assert!(i < this.fields.count()); | ty::Char
| ty::Int(_)
| ty::Uint(_)
| ty::Float(_)
| ty::FnPtr(_)
| ty::Never
| ty::FnDef(..)
| ty::GeneratorWitness(..)
| ty::Foreign(..)
| ty::Dynamic(..) => bug!("TyAndLayout::field_type({:?}): not applicable", this),
// Reuse the fat `*T` type as its own thin pointer data field. // Potentially-fat pointers.
// This provides information about, e.g., DST struct pointees ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
// (which may have no non-DST form), and will work as long assert!(i < this.fields.count());
// as the `Abi` or `FieldsShape` is checked by users.
if i == 0 {
let nil = tcx.mk_unit();
let ptr_ty = if this.ty.is_unsafe_ptr() {
tcx.mk_mut_ptr(nil)
} else {
tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
};
return MaybeResult::from(cx.layout_of(ptr_ty).to_result().map(
|mut ptr_layout| {
ptr_layout.ty = this.ty;
ptr_layout
},
));
}
match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { // Reuse the fat `*T` type as its own thin pointer data field.
ty::Slice(_) | ty::Str => tcx.types.usize, // This provides information about, e.g., DST struct pointees
ty::Dynamic(_, _) => { // (which may have no non-DST form), and will work as long
tcx.mk_imm_ref(tcx.lifetimes.re_static, tcx.mk_array(tcx.types.usize, 3)) // as the `Abi` or `FieldsShape` is checked by users.
/* FIXME: use actual fn pointers if i == 0 {
Warning: naively computing the number of entries in the let nil = tcx.mk_unit();
vtable by counting the methods on the trait + methods on let ptr_ty = if ty.is_unsafe_ptr() {
all parent traits does not work, because some methods can tcx.mk_mut_ptr(nil)
be not object safe and thus excluded from the vtable. } else {
Increase this counter if you tried to implement this but tcx.mk_mut_ref(tcx.lifetimes.re_static, nil)
failed to do it without duplicating a lot of code from };
other places in the compiler: 2 return TyMaybeWithLayout::TyAndLayout(MaybeResult::from(
tcx.mk_tup(&[ cx.layout_of(ptr_ty).to_result().map(|mut ptr_layout| {
tcx.mk_array(tcx.types.usize, 3), ptr_layout.ty = ty;
tcx.mk_array(Option<fn()>), ptr_layout
]) }),
*/ ));
}
match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() {
ty::Slice(_) | ty::Str => TyMaybeWithLayout::Ty(tcx.types.usize),
ty::Dynamic(_, _) => {
TyMaybeWithLayout::Ty(tcx.mk_imm_ref(
tcx.lifetimes.re_static,
tcx.mk_array(tcx.types.usize, 3),
))
/* FIXME: use actual fn pointers
Warning: naively computing the number of entries in the
vtable by counting the methods on the trait + methods on
all parent traits does not work, because some methods can
be not object safe and thus excluded from the vtable.
Increase this counter if you tried to implement this but
failed to do it without duplicating a lot of code from
other places in the compiler: 2
tcx.mk_tup(&[
tcx.mk_array(tcx.types.usize, 3),
tcx.mk_array(Option<fn()>),
])
*/
}
_ => bug!("TyAndLayout::field_type({:?}): not applicable", this),
} }
_ => bug!("TyAndLayout::field_type({:?}): not applicable", this),
} }
// Arrays and slices.
ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
// Tuples, generators and closures.
ty::Closure(_, ref substs) => {
ty_and_layout_kind(this, cx, i, substs.as_closure().tupled_upvars_ty())
}
ty::Generator(def_id, ref substs, _) => match this.variants {
Variants::Single { index } => TyMaybeWithLayout::Ty(
substs
.as_generator()
.state_tys(def_id, tcx)
.nth(index.as_usize())
.unwrap()
.nth(i)
.unwrap(),
),
Variants::Multiple { ref tag, tag_field, .. } => {
if i == tag_field {
return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
}
TyMaybeWithLayout::Ty(substs.as_generator().prefix_tys().nth(i).unwrap())
}
},
ty::Tuple(tys) => TyMaybeWithLayout::Ty(tys[i].expect_ty()),
// ADTs.
ty::Adt(def, substs) => {
match this.variants {
Variants::Single { index } => {
TyMaybeWithLayout::Ty(def.variants[index].fields[i].ty(tcx, substs))
}
// Discriminant field for enums (where applicable).
Variants::Multiple { ref tag, .. } => {
assert_eq!(i, 0);
return TyMaybeWithLayout::TyAndLayout(tag_layout(tag));
}
}
}
ty::Projection(_)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Opaque(..)
| ty::Param(_)
| ty::Infer(_)
| ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
} }
}
// Arrays and slices. cx.layout_of(match ty_and_layout_kind(this, cx, i, this.ty) {
ty::Array(element, _) | ty::Slice(element) => element, TyMaybeWithLayout::Ty(result) => result,
ty::Str => tcx.types.u8, TyMaybeWithLayout::TyAndLayout(result) => return result,
// Tuples, generators and closures.
ty::Closure(_, ref substs) => substs.as_closure().upvar_tys().nth(i).unwrap(),
ty::Generator(def_id, ref substs, _) => match this.variants {
Variants::Single { index } => substs
.as_generator()
.state_tys(def_id, tcx)
.nth(index.as_usize())
.unwrap()
.nth(i)
.unwrap(),
Variants::Multiple { ref tag, tag_field, .. } => {
if i == tag_field {
return tag_layout(tag);
}
substs.as_generator().prefix_tys().nth(i).unwrap()
}
},
ty::Tuple(tys) => tys[i].expect_ty(),
// ADTs.
ty::Adt(def, substs) => {
match this.variants {
Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs),
// Discriminant field for enums (where applicable).
Variants::Multiple { ref tag, .. } => {
assert_eq!(i, 0);
return tag_layout(tag);
}
}
}
ty::Projection(_)
| ty::Bound(..)
| ty::Placeholder(..)
| ty::Opaque(..)
| ty::Param(_)
| ty::Infer(_)
| ty::Error(_) => bug!("TyAndLayout::field_type: unexpected type `{}`", this.ty),
}) })
} }

View file

@ -94,16 +94,12 @@ where
_ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (), _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (),
ty::Closure(_, substs) => { ty::Closure(_, substs) => {
for upvar_ty in substs.as_closure().upvar_tys() { queue_type(self, substs.as_closure().tupled_upvars_ty());
queue_type(self, upvar_ty);
}
} }
ty::Generator(def_id, substs, _) => { ty::Generator(def_id, substs, _) => {
let substs = substs.as_generator(); let substs = substs.as_generator();
for upvar_ty in substs.upvar_tys() { queue_type(self, substs.tupled_upvars_ty());
queue_type(self, upvar_ty);
}
let witness = substs.witness(); let witness = substs.witness();
let interior_tys = match witness.kind() { let interior_tys = match witness.kind() {