]> git.lizzy.rs Git - rust.git/commitdiff
Auto merge of #40178 - arielb1:provide-destructors, r=eddyb
authorbors <bors@rust-lang.org>
Fri, 3 Mar 2017 05:16:10 +0000 (05:16 +0000)
committerbors <bors@rust-lang.org>
Fri, 3 Mar 2017 05:16:10 +0000 (05:16 +0000)
convert AdtDef::destructor to on-demand

This removes the `Cell` from `AdtDef`. Also, moving destructor validity
checking to on-demand (forced during item-type checking) ensures that
invalid destructors can't cause ICEs.

Fixes #38868.
Fixes #40132.

r? @eddyb

src/librustc/dep_graph/dep_node.rs
src/librustc/ty/maps.rs
src/librustc/ty/mod.rs
src/librustc/ty/util.rs
src/librustc_metadata/cstore_impl.rs
src/librustc_trans/collector.rs
src/librustc_trans/glue.rs
src/librustc_typeck/check/dropck.rs
src/librustc_typeck/check/mod.rs
src/librustc_typeck/lib.rs
src/test/compile-fail/issue-38868.rs [new file with mode: 0644]

index 2777c4d248710c42c0177608b62e5224ba6db2d3..254cae61152b90f4b20d74ac2f7d566c1f80ec9c 100644 (file)
@@ -79,8 +79,6 @@ pub enum DepNode<D: Clone + Debug> {
     Variance,
     WfCheck(D),
     TypeckItemType(D),
-    Dropck,
-    DropckImpl(D),
     UnusedTraitCheck,
     CheckConst(D),
     Privacy,
@@ -114,6 +112,7 @@ pub enum DepNode<D: Clone + Debug> {
     ItemSignature(D),
     TypeParamPredicates((D, D)),
     SizedConstraint(D),
+    AdtDestructor(D),
     AssociatedItemDefIds(D),
     InherentImpls(D),
     TypeckBodiesKrate,
@@ -229,7 +228,6 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
             EntryPoint => Some(EntryPoint),
             CheckEntryFn => Some(CheckEntryFn),
             Variance => Some(Variance),
-            Dropck => Some(Dropck),
             UnusedTraitCheck => Some(UnusedTraitCheck),
             Privacy => Some(Privacy),
             Reachability => Some(Reachability),
@@ -256,7 +254,6 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
             CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck),
             WfCheck(ref d) => op(d).map(WfCheck),
             TypeckItemType(ref d) => op(d).map(TypeckItemType),
-            DropckImpl(ref d) => op(d).map(DropckImpl),
             CheckConst(ref d) => op(d).map(CheckConst),
             IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
             MatchCheck(ref d) => op(d).map(MatchCheck),
@@ -272,6 +269,7 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
                 Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
             }
             SizedConstraint(ref d) => op(d).map(SizedConstraint),
+            AdtDestructor(ref d) => op(d).map(AdtDestructor),
             AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
             InherentImpls(ref d) => op(d).map(InherentImpls),
             TypeckTables(ref d) => op(d).map(TypeckTables),
@@ -303,4 +301,3 @@ pub fn map_def<E, OP>(&self, mut op: OP) -> Option<DepNode<E>>
 /// them even in the absence of a tcx.)
 #[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
 pub struct WorkProductId(pub String);
-
index fd1403b15bc892fb4414aec38e9891dae1080d5c..fcfdda8721f52fdcf6fec65c7d8e8aad2cf962fd 100644 (file)
@@ -333,6 +333,7 @@ fn default() -> Self {
 
     pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
     pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
+    pub adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
     pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>,
 
     /// Maps from def-id of a type or region parameter to its
index 2559a6709440a88f5d4a7f3a5dc40843e7de907c..d7efee06db2b56bb85f17180d3534c80a545094f 100644 (file)
@@ -1273,17 +1273,31 @@ pub fn for_item(tcx: TyCtxt<'a, 'tcx, 'tcx>, id: NodeId)
     }
 }
 
+#[derive(Copy, Clone, Debug)]
+pub struct Destructor {
+    /// The def-id of the destructor method
+    pub did: DefId,
+    /// Invoking the destructor of a dtorck type during usual cleanup
+    /// (e.g. the glue emitted for stack unwinding) requires all
+    /// lifetimes in the type-structure of `adt` to strictly outlive
+    /// the adt value itself.
+    ///
+    /// If `adt` is not dtorck, then the adt's destructor can be
+    /// invoked even when there are lifetimes in the type-structure of
+    /// `adt` that do not strictly outlive the adt value itself.
+    /// (This allows programs to make cyclic structures without
+    /// resorting to unasfe means; see RFCs 769 and 1238).
+    pub is_dtorck: bool,
+}
+
 bitflags! {
     flags AdtFlags: u32 {
         const NO_ADT_FLAGS        = 0,
         const IS_ENUM             = 1 << 0,
-        const IS_DTORCK           = 1 << 1, // is this a dtorck type?
-        const IS_DTORCK_VALID     = 1 << 2,
-        const IS_PHANTOM_DATA     = 1 << 3,
-        const IS_FUNDAMENTAL      = 1 << 4,
-        const IS_UNION            = 1 << 5,
-        const IS_BOX              = 1 << 6,
-        const IS_DTOR_VALID       = 1 << 7,
+        const IS_PHANTOM_DATA     = 1 << 1,
+        const IS_FUNDAMENTAL      = 1 << 2,
+        const IS_UNION            = 1 << 3,
+        const IS_BOX              = 1 << 4,
     }
 }
 
@@ -1325,8 +1339,7 @@ pub struct FieldDef {
 pub struct AdtDef {
     pub did: DefId,
     pub variants: Vec<VariantDef>,
-    destructor: Cell<Option<DefId>>,
-    flags: Cell<AdtFlags>,
+    flags: AdtFlags,
     pub repr: ReprOptions,
 }
 
@@ -1425,19 +1438,11 @@ fn new(tcx: TyCtxt,
         AdtDef {
             did: did,
             variants: variants,
-            flags: Cell::new(flags),
-            destructor: Cell::new(None),
+            flags: flags,
             repr: repr,
         }
     }
 
-    fn calculate_dtorck(&'gcx self, tcx: TyCtxt) {
-        if tcx.is_adt_dtorck(self) {
-            self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK);
-        }
-        self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID)
-    }
-
     #[inline]
     pub fn is_struct(&self) -> bool {
         !self.is_union() && !self.is_enum()
@@ -1445,12 +1450,12 @@ pub fn is_struct(&self) -> bool {
 
     #[inline]
     pub fn is_union(&self) -> bool {
-        self.flags.get().intersects(AdtFlags::IS_UNION)
+        self.flags.intersects(AdtFlags::IS_UNION)
     }
 
     #[inline]
     pub fn is_enum(&self) -> bool {
-        self.flags.get().intersects(AdtFlags::IS_ENUM)
+        self.flags.intersects(AdtFlags::IS_ENUM)
     }
 
     /// Returns the kind of the ADT - Struct or Enum.
@@ -1486,29 +1491,26 @@ pub fn variant_descr(&self) -> &'static str {
     /// alive; Otherwise, only the contents are required to be.
     #[inline]
     pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool {
-        if !self.flags.get().intersects(AdtFlags::IS_DTORCK_VALID) {
-            self.calculate_dtorck(tcx)
-        }
-        self.flags.get().intersects(AdtFlags::IS_DTORCK)
+        self.destructor(tcx).map_or(false, |d| d.is_dtorck)
     }
 
     /// Returns whether this type is #[fundamental] for the purposes
     /// of coherence checking.
     #[inline]
     pub fn is_fundamental(&self) -> bool {
-        self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL)
+        self.flags.intersects(AdtFlags::IS_FUNDAMENTAL)
     }
 
     /// Returns true if this is PhantomData<T>.
     #[inline]
     pub fn is_phantom_data(&self) -> bool {
-        self.flags.get().intersects(AdtFlags::IS_PHANTOM_DATA)
+        self.flags.intersects(AdtFlags::IS_PHANTOM_DATA)
     }
 
     /// Returns true if this is Box<T>.
     #[inline]
     pub fn is_box(&self) -> bool {
-        self.flags.get().intersects(AdtFlags::IS_BOX)
+        self.flags.intersects(AdtFlags::IS_BOX)
     }
 
     /// Returns whether this type has a destructor.
@@ -1568,38 +1570,6 @@ pub fn variant_of_def(&self, def: Def) -> &VariantDef {
         }
     }
 
-    pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
-        if self.flags.get().intersects(AdtFlags::IS_DTOR_VALID) {
-            return self.destructor.get();
-        }
-
-        let dtor = self.destructor_uncached(tcx);
-        self.destructor.set(dtor);
-        self.flags.set(self.flags.get() | AdtFlags::IS_DTOR_VALID);
-
-        dtor
-    }
-
-    fn destructor_uncached(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
-        let drop_trait = if let Some(def_id) = tcx.lang_items.drop_trait() {
-            def_id
-        } else {
-            return None;
-        };
-
-        queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, drop_trait));
-
-        let mut dtor = None;
-        let ty = tcx.item_type(self.did);
-        tcx.lookup_trait_def(drop_trait).for_each_relevant_impl(tcx, ty, |def_id| {
-            if let Some(item) = tcx.associated_items(def_id).next() {
-                dtor = Some(item.def_id);
-            }
-        });
-
-        dtor
-    }
-
     pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
                          -> impl Iterator<Item=ConstInt> + 'a {
         let repr_type = self.repr.discr_type();
@@ -1621,6 +1591,10 @@ pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
         })
     }
 
+    pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
+        queries::adt_destructor::get(tcx, DUMMY_SP, self.did)
+    }
+
     /// Returns a simpler type such that `Self: Sized` if and only
     /// if that type is Sized, or `TyErr` if this type is recursive.
     ///
index 49c25d25c604fb8c893dbecc6d1b5e50e4fe92b0..be1582066e393c4b99b6884e6b8f9a5c9dbe85ab 100644 (file)
@@ -10,7 +10,7 @@
 
 //! misc. type-system utilities too small to deserve their own file
 
-use hir::def_id::DefId;
+use hir::def_id::{DefId, LOCAL_CRATE};
 use hir::map::DefPathData;
 use infer::InferCtxt;
 use hir::map as hir_map;
@@ -20,6 +20,7 @@
 use ty::fold::TypeVisitor;
 use ty::layout::{Layout, LayoutError};
 use ty::TypeVariants::*;
+use util::common::ErrorReported;
 use util::nodemap::FxHashMap;
 use middle::lang_items;
 
@@ -32,7 +33,7 @@
 use std::intrinsics;
 use syntax::ast::{self, Name};
 use syntax::attr::{self, SignedInt, UnsignedInt};
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
 
 use hir;
 
@@ -346,22 +347,33 @@ pub fn type_id_hash(self, ty: Ty<'tcx>) -> u64 {
         hasher.finish()
     }
 
-    /// Returns true if this ADT is a dtorck type.
-    ///
-    /// Invoking the destructor of a dtorck type during usual cleanup
-    /// (e.g. the glue emitted for stack unwinding) requires all
-    /// lifetimes in the type-structure of `adt` to strictly outlive
-    /// the adt value itself.
-    ///
-    /// If `adt` is not dtorck, then the adt's destructor can be
-    /// invoked even when there are lifetimes in the type-structure of
-    /// `adt` that do not strictly outlive the adt value itself.
-    /// (This allows programs to make cyclic structures without
-    /// resorting to unasfe means; see RFCs 769 and 1238).
-    pub fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool {
-        let dtor_method = match adt.destructor(self) {
+    /// Calculate the destructor of a given type.
+    pub fn calculate_dtor(
+        self,
+        adt_did: DefId,
+        validate: &mut FnMut(Self, DefId) -> Result<(), ErrorReported>
+    ) -> Option<ty::Destructor> {
+        let drop_trait = if let Some(def_id) = self.lang_items.drop_trait() {
+            def_id
+        } else {
+            return None;
+        };
+
+        ty::queries::coherent_trait::get(self, DUMMY_SP, (LOCAL_CRATE, drop_trait));
+
+        let mut dtor_did = None;
+        let ty = self.item_type(adt_did);
+        self.lookup_trait_def(drop_trait).for_each_relevant_impl(self, ty, |impl_did| {
+            if let Some(item) = self.associated_items(impl_did).next() {
+                if let Ok(()) = validate(self, impl_did) {
+                    dtor_did = Some(item.def_id);
+                }
+            }
+        });
+
+        let dtor_did = match dtor_did {
             Some(dtor) => dtor,
-            None => return false
+            None => return None
         };
 
         // RFC 1238: if the destructor method is tagged with the
@@ -373,7 +385,8 @@ pub fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool {
         // Such access can be in plain sight (e.g. dereferencing
         // `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden
         // (e.g. calling `foo.0.clone()` of `Foo<T:Clone>`).
-        return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params");
+        let is_dtorck = !self.has_attr(dtor_did, "unsafe_destructor_blind_to_params");
+        Some(ty::Destructor { did: dtor_did, is_dtorck: is_dtorck })
     }
 
     pub fn closure_base_def_id(&self, def_id: DefId) -> DefId {
index 7b02280ef904bda504369b93dd1bb07a42428fa4..de53c91ba2d8fd60e21230711fcd63023e130f31 100644 (file)
@@ -76,6 +76,10 @@ pub fn provide<$lt>(providers: &mut Providers<$lt>) {
         tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx))
     }
     adt_def => { cdata.get_adt_def(def_id.index, tcx) }
+    adt_destructor => {
+        let _ = cdata;
+        tcx.calculate_dtor(def_id, &mut |_,_| Ok(()))
+    }
     variances => { Rc::new(cdata.get_item_variances(def_id.index)) }
     associated_item_def_ids => {
         let mut result = vec![];
index b12c1220b2b4de797a9c9f4be568a02839fd35eb..632762857ef37c3d0c984d0ca9de672899c57289 100644 (file)
@@ -753,12 +753,12 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
 
     // If the type implements Drop, also add a translation item for the
     // monomorphized Drop::drop() implementation.
-    let destructor_did = match ty.sty {
+    let destructor = match ty.sty {
         ty::TyAdt(def, _) => def.destructor(scx.tcx()),
         _ => None
     };
 
-    if let (Some(destructor_did), false) = (destructor_did, ty.is_box()) {
+    if let (Some(destructor), false) = (destructor, ty.is_box()) {
         use rustc::ty::ToPolyTraitRef;
 
         let drop_trait_def_id = scx.tcx()
@@ -778,9 +778,9 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
             _ => bug!()
         };
 
-        if should_trans_locally(scx.tcx(), destructor_did) {
+        if should_trans_locally(scx.tcx(), destructor.did) {
             let trans_item = create_fn_trans_item(scx,
-                                                  destructor_did,
+                                                  destructor.did,
                                                   substs,
                                                   scx.tcx().intern_substs(&[]));
             output.push(trans_item);
index 32fc3d5af24451f21d97a2a39d6c176329f1dd26..35ebd67b5f8c19f8555d615397b976676d960588 100644 (file)
@@ -265,7 +265,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
                 traits::VtableImpl(data) => data,
                 _ => bug!("dtor for {:?} is not an impl???", t)
             };
-            let dtor_did = def.destructor(tcx).unwrap();
+            let dtor_did = def.destructor(tcx).unwrap().did;
             let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
             let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
             let llret;
index 07cc35ed67bbb76ab86bf82bd3e446544cd0f7e1..90d2a15cf08637f4b94ae961aaeed13cdde50fb6 100644 (file)
@@ -17,6 +17,7 @@
 use rustc::ty::subst::{Subst, Substs};
 use rustc::ty::{self, AdtKind, Ty, TyCtxt};
 use rustc::traits::{self, ObligationCause, Reveal};
+use util::common::ErrorReported;
 use util::nodemap::FxHashSet;
 
 use syntax::ast;
@@ -40,7 +41,8 @@
 ///    cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
 ///
 pub fn check_drop_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                 drop_impl_did: DefId) -> Result<(), ()> {
+                                 drop_impl_did: DefId)
+                                 -> Result<(), ErrorReported> {
     let dtor_self_type = tcx.item_type(drop_impl_did);
     let dtor_predicates = tcx.item_predicates(drop_impl_did);
     match dtor_self_type.sty {
@@ -72,7 +74,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
     drop_impl_did: DefId,
     drop_impl_ty: Ty<'tcx>,
     self_type_did: DefId)
-    -> Result<(), ()>
+    -> Result<(), ErrorReported>
 {
     let drop_impl_node_id = tcx.hir.as_local_node_id(drop_impl_did).unwrap();
     let self_type_node_id = tcx.hir.as_local_node_id(self_type_did).unwrap();
@@ -106,14 +108,14 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
                                "Use same sequence of generic type and region \
                                 parameters that is on the struct/enum definition")
                     .emit();
-                return Err(());
+                return Err(ErrorReported);
             }
         }
 
         if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
             // this could be reached when we get lazy normalization
             infcx.report_fulfillment_errors(errors);
-            return Err(());
+            return Err(ErrorReported);
         }
 
         let free_regions = FreeRegionMap::new();
@@ -130,8 +132,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
     dtor_predicates: &ty::GenericPredicates<'tcx>,
     self_type_did: DefId,
     self_to_impl_substs: &Substs<'tcx>)
-    -> Result<(), ()>
+    -> Result<(), ErrorReported>
 {
+    let mut result = Ok(());
 
     // Here is an example, analogous to that from
     // `compare_impl_method`.
@@ -207,13 +210,11 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
                            "The same requirement must be part of \
                             the struct/enum definition")
                 .emit();
+            result = Err(ErrorReported);
         }
     }
 
-    if tcx.sess.has_errors() {
-        return Err(());
-    }
-    Ok(())
+    result
 }
 
 /// check_safety_of_destructor_if_necessary confirms that the type
@@ -556,7 +557,7 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
             // attributes attached to the impl's generics.
             let dtor_method = adt_def.destructor(tcx)
                 .expect("dtorck type without destructor impossible");
-            let method = tcx.associated_item(dtor_method);
+            let method = tcx.associated_item(dtor_method.did);
             let impl_def_id = method.container.id();
             let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs);
             return DropckKind::RevisedSelf(revised_ty);
index ec94e1f75e08c7691be467b0cf999efc0bb0bd21..126cd2302fb27b57414e8860c26cc00e0725915e 100644 (file)
@@ -548,31 +548,12 @@ pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult
     })
 }
 
-pub fn check_drop_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
-    tcx.sess.track_errors(|| {
-        let _task = tcx.dep_graph.in_task(DepNode::Dropck);
-        let drop_trait = match tcx.lang_items.drop_trait() {
-            Some(id) => tcx.lookup_trait_def(id), None => { return }
-        };
-        drop_trait.for_each_impl(tcx, |drop_impl_did| {
-            let _task = tcx.dep_graph.in_task(DepNode::DropckImpl(drop_impl_did));
-            if drop_impl_did.is_local() {
-                match dropck::check_drop_impl(tcx, drop_impl_did) {
-                    Ok(()) => {}
-                    Err(()) => {
-                        assert!(tcx.sess.has_errors());
-                    }
-                }
-            }
-        });
-    })
-}
-
 pub fn provide(providers: &mut Providers) {
     *providers = Providers {
         typeck_tables,
         closure_type,
         closure_kind,
+        adt_destructor,
         ..*providers
     };
 }
@@ -591,6 +572,12 @@ fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
     tcx.item_tables(def_id).closure_kinds[&node_id]
 }
 
+fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            def_id: DefId)
+                            -> Option<ty::Destructor> {
+    tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl)
+}
+
 fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                            def_id: DefId)
                            -> &'tcx ty::TypeckTables<'tcx> {
@@ -840,9 +827,11 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                           id: ast::NodeId,
                           span: Span) {
     let def_id = tcx.hir.local_def_id(id);
+    let def = tcx.lookup_adt_def(def_id);
+    def.destructor(tcx); // force the destructor to be evaluated
     check_representable(tcx, span, def_id);
 
-    if tcx.lookup_adt_def(def_id).repr.simd {
+    if def.repr.simd {
         check_simd(tcx, span, def_id);
     }
 }
@@ -850,7 +839,10 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
 fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
                          id: ast::NodeId,
                          span: Span) {
-    check_representable(tcx, span, tcx.hir.local_def_id(id));
+    let def_id = tcx.hir.local_def_id(id);
+    let def = tcx.lookup_adt_def(def_id);
+    def.destructor(tcx); // force the destructor to be evaluated
+    check_representable(tcx, span, def_id);
 }
 
 pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
@@ -865,10 +857,10 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item
         tcx.item_tables(tcx.hir.local_def_id(it.id));
       }
       hir::ItemEnum(ref enum_definition, _) => {
-        check_enum_variants(tcx,
-                            it.span,
-                            &enum_definition.variants,
-                            it.id);
+        check_enum(tcx,
+                   it.span,
+                   &enum_definition.variants,
+                   it.id);
       }
       hir::ItemFn(..) => {} // entirely within check_item_body
       hir::ItemImpl(.., ref impl_item_refs) => {
@@ -1261,12 +1253,13 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId
 }
 
 #[allow(trivial_numeric_casts)]
-pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
-                                     sp: Span,
-                                     vs: &'tcx [hir::Variant],
-                                     id: ast::NodeId) {
+pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
+                            sp: Span,
+                            vs: &'tcx [hir::Variant],
+                            id: ast::NodeId) {
     let def_id = tcx.hir.local_def_id(id);
     let def = tcx.lookup_adt_def(def_id);
+    def.destructor(tcx); // force the destructor to be evaluated
 
     if vs.is_empty() && tcx.has_attr(def_id, "repr") {
         struct_span_err!(
index 2c325d46c0bc060ff3e8b1aa4c6ca90a4bfad11e..df1c94dc19b59eb761a9bae3697bf9fff3517b48 100644 (file)
@@ -322,8 +322,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
 
     time(time_passes, "item-bodies checking", || check::check_item_bodies(tcx))?;
 
-    time(time_passes, "drop-impl checking", || check::check_drop_impls(tcx))?;
-
     check_unused::check_crate(tcx);
     check_for_entry_fn(tcx);
 
diff --git a/src/test/compile-fail/issue-38868.rs b/src/test/compile-fail/issue-38868.rs
new file mode 100644 (file)
index 0000000..c7e1da7
--- /dev/null
@@ -0,0 +1,23 @@
+// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
+// file at the top-level directory of this distribution and at
+// http://rust-lang.org/COPYRIGHT.
+//
+// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
+// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
+// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
+// option. This file may not be copied, modified, or distributed
+// except according to those terms.
+
+pub struct List<T> {
+    head: T,
+}
+
+impl Drop for List<i32> { //~ ERROR E0366
+    fn drop(&mut self) {
+        panic!()
+    }
+}
+
+fn main() {
+    List { head: 0 };
+}