]> git.lizzy.rs Git - rust.git/commitdiff
Be cautious of calling upvar_tys before mir
authorAman Arora <me@aman-arora.com>
Sat, 7 Nov 2020 06:04:27 +0000 (01:04 -0500)
committerRoxane <roxane.fruytier@hotmail.com>
Mon, 30 Nov 2020 00:20:28 +0000 (19:20 -0500)
compiler/rustc_middle/src/ty/layout.rs
compiler/rustc_ty_utils/src/needs_drop.rs

index 8bdc7efa0bb611b851f2f4bb92ec383604deed05..00fea91fdfcb81d342042cf7d656b761e7efcd9d 100644 (file)
@@ -2105,118 +2105,148 @@ fn for_variant(
     }
 
     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<C: LayoutOf> {
+            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),
-
-            // Potentially-fat pointers.
-            ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
-                assert!(i < this.fields.count());
-
-                // 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
-                        },
-                    ));
-                }
+        fn ty_and_layout_kind<
+            C: LayoutOf<Ty = Ty<'tcx>, TyAndLayout: MaybeResult<TyAndLayout<'tcx>>>
+                + HasTyCtxt<'tcx>
+                + HasParamEnv<'tcx>,
+        >(
+            this: TyAndLayout<'tcx>,
+            cx: &C,
+            i: usize,
+            ty: C::Ty,
+        ) -> TyMaybeWithLayout<C> {
+            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),
+                }))
+            };
 
-                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<fn()>),
-                        ])
-                        */
+            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),
+
+                // Potentially-fat pointers.
+                ty::Ref(_, pointee, _) | ty::RawPtr(ty::TypeAndMut { ty: pointee, .. }) => {
+                    assert!(i < this.fields.count());
+
+                    // 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
+                            }),
+                        ));
                     }
-                    _ => bug!("TyAndLayout::field_type({:?}): not applicable", this),
-                }
-            }
 
-            // 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);
+                    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),
                     }
-                    substs.as_generator().prefix_tys().nth(i).unwrap()
                 }
-            },
 
-            ty::Tuple(tys) => tys[i].expect_ty(),
+                // Arrays and slices.
+                ty::Array(element, _) | ty::Slice(element) => TyMaybeWithLayout::Ty(element),
+                ty::Str => TyMaybeWithLayout::Ty(tcx.types.u8),
 
-            // ADTs.
-            ty::Adt(def, substs) => {
-                match this.variants {
-                    Variants::Single { index } => def.variants[index].fields[i].ty(tcx, substs),
+                // 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 tag_layout(tag);
+                        // 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),
             }
+        }
 
-            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,
         })
     }
 
index d62fc764c76d719e5d859f1cddc72e5006a9067c..64f82817d3944e4636237b96c744f4d9d38e3bd3 100644 (file)
@@ -94,16 +94,12 @@ fn next(&mut self) -> Option<NeedsDropResult<Ty<'tcx>>> {
                     _ 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() {