Be cautious of calling upvar_tys before mir
This commit is contained in:
parent
5da2bf197d
commit
e35e46c113
2 changed files with 136 additions and 110 deletions
|
@ -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),
|
|
||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -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() {
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue