From e35e46c1139d292ca0b352416d01b38bcf96fd69 Mon Sep 17 00:00:00 2001 From: Aman Arora Date: Sat, 7 Nov 2020 01:04:27 -0500 Subject: [PATCH] Be cautious of calling upvar_tys before mir --- compiler/rustc_middle/src/ty/layout.rs | 238 ++++++++++++---------- compiler/rustc_ty_utils/src/needs_drop.rs | 8 +- 2 files changed, 136 insertions(+), 110 deletions(-) diff --git a/compiler/rustc_middle/src/ty/layout.rs b/compiler/rustc_middle/src/ty/layout.rs index 8bdc7efa0bb..00fea91fdfc 100644 --- a/compiler/rustc_middle/src/ty/layout.rs +++ b/compiler/rustc_middle/src/ty/layout.rs @@ -2105,118 +2105,148 @@ where } fn field(this: TyAndLayout<'tcx>, cx: &C, i: usize) -> C::TyAndLayout { - let tcx = cx.tcx(); - 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), - })) - }; + enum TyMaybeWithLayout { + Ty(C::Ty), + TyAndLayout(C::TyAndLayout), + } - cx.layout_of(match *this.ty.kind() { - ty::Bool - | 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), + fn ty_and_layout_kind< + C: LayoutOf, TyAndLayout: MaybeResult>> + + HasTyCtxt<'tcx> + + HasParamEnv<'tcx>, + >( + this: TyAndLayout<'tcx>, + cx: &C, + i: usize, + ty: C::Ty, + ) -> TyMaybeWithLayout { + let tcx = cx.tcx(); + 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. - ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { - assert!(i < this.fields.count()); + match *ty.kind() { + ty::Bool + | 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. - // This provides information about, e.g., DST struct pointees - // (which may have no non-DST form), and will work as long - // 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 - }, - )); - } + // Potentially-fat pointers. + ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => { + assert!(i < this.fields.count()); - match tcx.struct_tail_erasing_lifetimes(pointee, cx.param_env()).kind() { - ty::Slice(_) | ty::Str => tcx.types.usize, - ty::Dynamic(_, _) => { - 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), - ]) - */ + // Reuse the fat `*T` type as its own thin pointer data field. + // This provides information about, e.g., DST struct pointees + // (which may have no non-DST form), and will work as long + // as the `Abi` or `FieldsShape` is checked by users. + if i == 0 { + let nil = tcx.mk_unit(); + let ptr_ty = if ty.is_unsafe_ptr() { + tcx.mk_mut_ptr(nil) + } else { + tcx.mk_mut_ref(tcx.lifetimes.re_static, nil) + }; + return TyMaybeWithLayout::TyAndLayout(MaybeResult::from( + cx.layout_of(ptr_ty).to_result().map(|mut ptr_layout| { + ptr_layout.ty = ty; + 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), + ]) + */ + } + _ => 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. - ty::Array(element, _) | ty::Slice(element) => element, - ty::Str => tcx.types.u8, - - // 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), + cx.layout_of(match ty_and_layout_kind(this, cx, i, this.ty) { + TyMaybeWithLayout::Ty(result) => result, + TyMaybeWithLayout::TyAndLayout(result) => return result, }) } diff --git a/compiler/rustc_ty_utils/src/needs_drop.rs b/compiler/rustc_ty_utils/src/needs_drop.rs index d62fc764c76..64f82817d39 100644 --- a/compiler/rustc_ty_utils/src/needs_drop.rs +++ b/compiler/rustc_ty_utils/src/needs_drop.rs @@ -94,16 +94,12 @@ where _ if component.is_copy_modulo_regions(tcx.at(DUMMY_SP), self.param_env) => (), ty::Closure(_, substs) => { - for upvar_ty in substs.as_closure().upvar_tys() { - queue_type(self, upvar_ty); - } + queue_type(self, substs.as_closure().tupled_upvars_ty()); } ty::Generator(def_id, substs, _) => { let substs = substs.as_generator(); - for upvar_ty in substs.upvar_tys() { - queue_type(self, upvar_ty); - } + queue_type(self, substs.tupled_upvars_ty()); let witness = substs.witness(); let interior_tys = match witness.kind() {