about summary refs log tree commit diff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/librustc/middle/check_const.rs2
-rw-r--r--src/librustc/middle/expr_use_visitor.rs5
-rw-r--r--src/librustc/middle/infer/higher_ranked/mod.rs58
-rw-r--r--src/librustc/middle/infer/mod.rs9
-rw-r--r--src/librustc/middle/infer/region_inference/mod.rs2
-rw-r--r--src/librustc/middle/reachable.rs8
-rw-r--r--src/librustc/middle/ty.rs131
-rw-r--r--src/librustc/util/ppaux.rs2
-rw-r--r--src/librustc_borrowck/borrowck/check_loans.rs2
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs2
-rw-r--r--src/librustc_borrowck/borrowck/gather_loans/move_error.rs2
-rw-r--r--src/librustc_lint/builtin.rs18
-rw-r--r--src/librustc_trans/trans/adt.rs4
-rw-r--r--src/librustc_trans/trans/expr.rs2
-rw-r--r--src/librustc_trans/trans/glue.rs115
-rw-r--r--src/librustc_trans/trans/type_of.rs8
-rw-r--r--src/librustc_typeck/check/dropck.rs76
-rw-r--r--src/librustc_typeck/coherence/mod.rs4
-rw-r--r--src/test/compile-fail/reject-specialized-drops-8142.rs8
-rw-r--r--src/test/run-pass/issue-27997.rs48
20 files changed, 256 insertions, 250 deletions
diff --git a/src/librustc/middle/check_const.rs b/src/librustc/middle/check_const.rs
index 1ed43a57041..9153fd6484e 100644
--- a/src/librustc/middle/check_const.rs
+++ b/src/librustc/middle/check_const.rs
@@ -548,7 +548,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
                         e: &ast::Expr, node_ty: Ty<'tcx>) {
     match node_ty.sty {
         ty::TyStruct(def, _) |
-        ty::TyEnum(def, _) if def.has_dtor(v.tcx) => {
+        ty::TyEnum(def, _) if def.has_dtor() => {
             v.add_qualif(ConstQualif::NEEDS_DROP);
             if v.mode != Mode::Var {
                 v.tcx.sess.span_err(e.span,
diff --git a/src/librustc/middle/expr_use_visitor.rs b/src/librustc/middle/expr_use_visitor.rs
index ce03e10418d..d8f3ff3d9cb 100644
--- a/src/librustc/middle/expr_use_visitor.rs
+++ b/src/librustc/middle/expr_use_visitor.rs
@@ -239,8 +239,9 @@ impl OverloadedCallType {
 // mem_categorization, it requires a TYPER, which is a type that
 // supplies types from the tree. After type checking is complete, you
 // can just use the tcx as the typer.
-
-pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d> {
+//
+// FIXME(stage0): the :'t here is probably only important for stage0
+pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d+'t> {
     typer: &'t infer::InferCtxt<'a, 'tcx>,
     mc: mc::MemCategorizationContext<'t, 'a, 'tcx>,
     delegate: &'d mut (Delegate<'tcx>+'d),
diff --git a/src/librustc/middle/infer/higher_ranked/mod.rs b/src/librustc/middle/infer/higher_ranked/mod.rs
index fb8da9b65da..0c539a5d0e0 100644
--- a/src/librustc/middle/infer/higher_ranked/mod.rs
+++ b/src/librustc/middle/infer/higher_ranked/mod.rs
@@ -14,7 +14,6 @@
 use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
 use super::combine::CombineFields;
 
-use middle::subst;
 use middle::ty::{self, TypeError, Binder};
 use middle::ty_fold::{self, TypeFoldable};
 use middle::ty_relate::{Relate, RelateResult, TypeRelation};
@@ -455,63 +454,6 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
     }
 }
 
-/// Constructs and returns a substitution that, for a given type
-/// scheme parameterized by `generics`, will replace every generic
-/// parameter in the type with a skolemized type/region (which one can
-/// think of as a "fresh constant", except at the type/region level of
-/// reasoning).
-///
-/// Since we currently represent bound/free type parameters in the
-/// same way, this only has an effect on regions.
-///
-/// (Note that unlike a substitution from `ty::construct_free_substs`,
-/// this inserts skolemized regions rather than free regions; this
-/// allows one to use `fn leak_check` to catch attmepts to unify the
-/// skolemized regions with e.g. the `'static` lifetime)
-pub fn construct_skolemized_substs<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
-                                            generics: &ty::Generics<'tcx>,
-                                            snapshot: &CombinedSnapshot)
-                                            -> (subst::Substs<'tcx>, SkolemizationMap)
-{
-    let mut map = FnvHashMap();
-
-    // map T => T
-    let mut types = subst::VecPerParamSpace::empty();
-    push_types_from_defs(infcx.tcx, &mut types, generics.types.as_slice());
-
-    // map early- or late-bound 'a => fresh 'a
-    let mut regions = subst::VecPerParamSpace::empty();
-    push_region_params(infcx, &mut map, &mut regions, generics.regions.as_slice(), snapshot);
-
-    let substs = subst::Substs { types: types,
-                                 regions: subst::NonerasedRegions(regions) };
-    return (substs, map);
-
-    fn push_region_params<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
-                                   map: &mut SkolemizationMap,
-                                   regions: &mut subst::VecPerParamSpace<ty::Region>,
-                                   region_params: &[ty::RegionParameterDef],
-                                   snapshot: &CombinedSnapshot)
-    {
-        for r in region_params {
-            let br = r.to_bound_region();
-            let skol_var = infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot);
-            let sanity_check = map.insert(br, skol_var);
-            assert!(sanity_check.is_none());
-            regions.push(r.space, skol_var);
-        }
-    }
-
-    fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>,
-                                  types: &mut subst::VecPerParamSpace<ty::Ty<'tcx>>,
-                                  defs: &[ty::TypeParameterDef<'tcx>]) {
-        for def in defs {
-            let ty = tcx.mk_param_from_def(def);
-            types.push(def.space, ty);
-        }
-    }
-}
-
 pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
                                                binder: &ty::Binder<T>,
                                                snapshot: &CombinedSnapshot)
diff --git a/src/librustc/middle/infer/mod.rs b/src/librustc/middle/infer/mod.rs
index 4e8ed01c6b9..158ef745de3 100644
--- a/src/librustc/middle/infer/mod.rs
+++ b/src/librustc/middle/infer/mod.rs
@@ -948,15 +948,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         })
     }
 
-    pub fn construct_skolemized_subst(&self,
-                                      generics: &ty::Generics<'tcx>,
-                                      snapshot: &CombinedSnapshot)
-                                      -> (subst::Substs<'tcx>, SkolemizationMap) {
-        /*! See `higher_ranked::construct_skolemized_subst` */
-
-        higher_ranked::construct_skolemized_substs(self, generics, snapshot)
-    }
-
     pub fn skolemize_late_bound_regions<T>(&self,
                                            value: &ty::Binder<T>,
                                            snapshot: &CombinedSnapshot)
diff --git a/src/librustc/middle/infer/region_inference/mod.rs b/src/librustc/middle/infer/region_inference/mod.rs
index 1785fe09f87..d81f8e0ae90 100644
--- a/src/librustc/middle/infer/region_inference/mod.rs
+++ b/src/librustc/middle/infer/region_inference/mod.rs
@@ -373,7 +373,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
 
         let sc = self.skolemization_count.get();
         self.skolemization_count.set(sc + 1);
-        ReSkolemized(sc, br)
+        ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br)
     }
 
     pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region {
diff --git a/src/librustc/middle/reachable.rs b/src/librustc/middle/reachable.rs
index 206e1f2ba64..4eef0001696 100644
--- a/src/librustc/middle/reachable.rs
+++ b/src/librustc/middle/reachable.rs
@@ -355,9 +355,11 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
     // this properly would result in the necessity of computing *type*
     // reachability, which might result in a compile time loss.
     fn mark_destructors_reachable(&mut self) {
-        for (_, destructor_def_id) in self.tcx.destructor_for_type.borrow().iter() {
-            if destructor_def_id.is_local() {
-                self.reachable_symbols.insert(destructor_def_id.node);
+        for adt in self.tcx.adt_defs() {
+            if let Some(destructor_def_id) = adt.destructor() {
+                if destructor_def_id.is_local() {
+                    self.reachable_symbols.insert(destructor_def_id.node);
+                }
             }
         }
     }
diff --git a/src/librustc/middle/ty.rs b/src/librustc/middle/ty.rs
index eff560653c1..e9be9010d4a 100644
--- a/src/librustc/middle/ty.rs
+++ b/src/librustc/middle/ty.rs
@@ -112,7 +112,7 @@ pub struct CrateAnalysis {
 #[derive(Copy, Clone)]
 pub enum DtorKind {
     NoDtor,
-    TraitDtor(DefId, bool)
+    TraitDtor(bool)
 }
 
 impl DtorKind {
@@ -126,7 +126,7 @@ impl DtorKind {
     pub fn has_drop_flag(&self) -> bool {
         match self {
             &NoDtor => false,
-            &TraitDtor(_, flag) => flag
+            &TraitDtor(flag) => flag
         }
     }
 }
@@ -797,12 +797,6 @@ pub struct ctxt<'tcx> {
     /// True if the variance has been computed yet; false otherwise.
     pub variance_computed: Cell<bool>,
 
-    /// A mapping from the def ID of an enum or struct type to the def ID
-    /// of the method that implements its destructor. If the type is not
-    /// present in this map, it does not have a destructor. This map is
-    /// populated during the coherence phase of typechecking.
-    pub destructor_for_type: RefCell<DefIdMap<DefId>>,
-
     /// A method will be in this list if and only if it is a destructor.
     pub destructors: RefCell<DefIdSet>,
 
@@ -1502,7 +1496,62 @@ pub struct DebruijnIndex {
     pub depth: u32,
 }
 
-/// Representation of regions:
+/// Representation of regions.
+///
+/// Unlike types, most region variants are "fictitious", not concrete,
+/// regions. Among these, `ReStatic`, `ReEmpty` and `ReScope` are the only
+/// ones representing concrete regions.
+///
+/// ## Bound Regions
+///
+/// These are regions that are stored behind a binder and must be substituted
+/// with some concrete region before being used. There are 2 kind of
+/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef,
+/// and are substituted by a Substs,  and late-bound, which are part of
+/// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by
+/// the likes of `liberate_late_bound_regions`. The distinction exists
+/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
+///
+/// Unlike TyParam-s, bound regions are not supposed to exist "in the wild"
+/// outside their binder, e.g. in types passed to type inference, and
+/// should first be substituted (by skolemized regions, free regions,
+/// or region variables).
+///
+/// ## Skolemized and Free Regions
+///
+/// One often wants to work with bound regions without knowing their precise
+/// identity. For example, when checking a function, the lifetime of a borrow
+/// can end up being assigned to some region parameter. In these cases,
+/// it must be ensured that bounds on the region can't be accidentally
+/// assumed without being checked.
+///
+/// The process of doing that is called "skolemization". The bound regions
+/// are replaced by skolemized markers, which don't satisfy any relation
+/// not explicity provided.
+///
+/// There are 2 kinds of skolemized regions in rustc: `ReFree` and
+/// `ReSkolemized`. When checking an item's body, `ReFree` is supposed
+/// to be used. These also support explicit bounds: both the internally-stored
+/// *scope*, which the region is assumed to outlive, as well as other
+/// relations stored in the `FreeRegionMap`. Note that these relations
+/// aren't checked when you `make_subregion` (or `mk_eqty`), only by
+/// `resolve_regions_and_report_errors`.
+///
+/// When working with higher-ranked types, some region relations aren't
+/// yet known, so you can't just call `resolve_regions_and_report_errors`.
+/// `ReSkolemized` is designed for this purpose. In these contexts,
+/// there's also the risk that some inference variable laying around will
+/// get unified with your skolemized region: if you want to check whether
+/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
+/// with a skolemized region `'%a`, the variable `'_` would just be
+/// instantiated to the skolemized region `'%a`, which is wrong because
+/// the inference variable is supposed to satisfy the relation
+/// *for every value of the skolemized region*. To ensure that doesn't
+/// happen, you can use `leak_check`. This is more clearly explained
+/// by infer/higher_ranked/README.md.
+///
+/// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
+/// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
 #[derive(Clone, PartialEq, Eq, Hash, Copy)]
 pub enum Region {
     // Region bound in a type or fn declaration which will be
@@ -1532,7 +1581,7 @@ pub enum Region {
 
     /// A skolemized region - basically the higher-ranked version of ReFree.
     /// Should not exist after typeck.
-    ReSkolemized(u32, BoundRegion),
+    ReSkolemized(SkolemizedRegionVid, BoundRegion),
 
     /// Empty lifetime is for data that is never accessed.
     /// Bottom in the region lattice. We treat ReEmpty somewhat
@@ -2169,6 +2218,11 @@ pub struct RegionVid {
 }
 
 #[derive(Clone, Copy, PartialEq, Eq, Hash)]
+pub struct SkolemizedRegionVid {
+    pub index: u32
+}
+
+#[derive(Clone, Copy, PartialEq, Eq, Hash)]
 pub enum InferTy {
     TyVar(TyVid),
     IntVar(IntVid),
@@ -2997,7 +3051,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
             _ => return Err(TypeIsStructural),
         };
 
-        if adt.has_dtor(tcx) {
+        if adt.has_dtor() {
             return Err(TypeHasDestructor)
         }
 
@@ -3202,6 +3256,7 @@ bitflags! {
         const IS_PHANTOM_DATA     = 1 << 3,
         const IS_SIMD             = 1 << 4,
         const IS_FUNDAMENTAL      = 1 << 5,
+        const IS_NO_DROP_FLAG     = 1 << 6,
     }
 }
 
@@ -3252,6 +3307,7 @@ pub struct FieldDefData<'tcx, 'container: 'tcx> {
 pub struct AdtDefData<'tcx, 'container: 'tcx> {
     pub did: DefId,
     pub variants: Vec<VariantDefData<'tcx, 'container>>,
+    destructor: Cell<Option<DefId>>,
     flags: Cell<AdtFlags>,
 }
 
@@ -3287,6 +3343,9 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
         if attr::contains_name(&attrs, "fundamental") {
             flags = flags | AdtFlags::IS_FUNDAMENTAL;
         }
+        if attr::contains_name(&attrs, "unsafe_no_drop_flag") {
+            flags = flags | AdtFlags::IS_NO_DROP_FLAG;
+        }
         if tcx.lookup_simd(did) {
             flags = flags | AdtFlags::IS_SIMD;
         }
@@ -3300,6 +3359,7 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
             did: did,
             variants: variants,
             flags: Cell::new(flags),
+            destructor: Cell::new(None)
         }
     }
 
@@ -3350,8 +3410,11 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
     }
 
     /// Returns whether this type has a destructor.
-    pub fn has_dtor(&self, tcx: &ctxt<'tcx>) -> bool {
-        tcx.destructor_for_type.borrow().contains_key(&self.did)
+    pub fn has_dtor(&self) -> bool {
+        match self.dtor_kind() {
+            NoDtor => false,
+            TraitDtor(..) => true
+        }
     }
 
     /// Asserts this is a struct and returns the struct's unique
@@ -3413,6 +3476,24 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
             _ => panic!("unexpected def {:?} in variant_of_def", def)
         }
     }
+
+    pub fn destructor(&self) -> Option<DefId> {
+        self.destructor.get()
+    }
+
+    pub fn set_destructor(&self, dtor: DefId) {
+        assert!(self.destructor.get().is_none());
+        self.destructor.set(Some(dtor));
+    }
+
+    pub fn dtor_kind(&self) -> DtorKind {
+        match self.destructor.get() {
+            Some(_) => {
+                TraitDtor(!self.flags.get().intersects(AdtFlags::IS_NO_DROP_FLAG))
+            }
+            None => NoDtor,
+        }
+    }
 }
 
 impl<'tcx, 'container> VariantDefData<'tcx, 'container> {
@@ -3796,7 +3877,6 @@ impl<'tcx> ctxt<'tcx> {
             normalized_cache: RefCell::new(FnvHashMap()),
             lang_items: lang_items,
             provided_method_sources: RefCell::new(DefIdMap()),
-            destructor_for_type: RefCell::new(DefIdMap()),
             destructors: RefCell::new(DefIdSet()),
             inherent_impls: RefCell::new(DefIdMap()),
             impl_items: RefCell::new(DefIdMap()),
@@ -4619,7 +4699,7 @@ impl<'tcx> TyS<'tcx> {
                             })
                         });
 
-                    if def.has_dtor(cx) {
+                    if def.has_dtor() {
                         res = res | TC::OwnsDtor;
                     }
 
@@ -5957,18 +6037,6 @@ impl<'tcx> ctxt<'tcx> {
         self.with_path(id, |path| ast_map::path_to_string(path))
     }
 
-    /* If struct_id names a struct with a dtor. */
-    pub fn ty_dtor(&self, struct_id: DefId) -> DtorKind {
-        match self.destructor_for_type.borrow().get(&struct_id) {
-            Some(&method_def_id) => {
-                let flag = !self.has_attr(struct_id, "unsafe_no_drop_flag");
-
-                TraitDtor(method_def_id, flag)
-            }
-            None => NoDtor,
-        }
-    }
-
     pub fn with_path<T, F>(&self, id: DefId, f: F) -> T where
         F: FnOnce(ast_map::PathElems) -> T,
     {
@@ -6053,6 +6121,11 @@ impl<'tcx> ctxt<'tcx> {
         self.lookup_adt_def_master(did)
     }
 
+    /// Return the list of all interned ADT definitions
+    pub fn adt_defs(&self) -> Vec<AdtDef<'tcx>> {
+        self.adt_defs.borrow().values().cloned().collect()
+    }
+
     /// Given the did of an item, returns its full set of predicates.
     pub fn lookup_predicates(&self, did: DefId) -> GenericPredicates<'tcx> {
         lookup_locally_or_in_crate_store(
@@ -6700,8 +6773,8 @@ impl<'tcx> ctxt<'tcx> {
     /// Returns true if this ADT is a dtorck type, i.e. whether it being
     /// safe for destruction requires it to be alive
     fn is_adt_dtorck(&self, adt: AdtDef<'tcx>) -> bool {
-        let dtor_method = match self.destructor_for_type.borrow().get(&adt.did) {
-            Some(dtor) => *dtor,
+        let dtor_method = match adt.destructor() {
+            Some(dtor) => dtor,
             None => return false
         };
         let impl_did = self.impl_of_method(dtor_method).unwrap_or_else(|| {
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 48c2e1e6dca..ac51f46a7e9 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -418,7 +418,7 @@ impl fmt::Debug for ty::Region {
             }
 
             ty::ReSkolemized(id, ref bound_region) => {
-                write!(f, "ReSkolemized({}, {:?})", id, bound_region)
+                write!(f, "ReSkolemized({}, {:?})", id.index, bound_region)
             }
 
             ty::ReEmpty => write!(f, "ReEmpty")
diff --git a/src/librustc_borrowck/borrowck/check_loans.rs b/src/librustc_borrowck/borrowck/check_loans.rs
index 3e3ce5c7be0..7f9128228a5 100644
--- a/src/librustc_borrowck/borrowck/check_loans.rs
+++ b/src/librustc_borrowck/borrowck/check_loans.rs
@@ -747,7 +747,7 @@ impl<'a, 'tcx> CheckLoanCtxt<'a, 'tcx> {
             }
             LpExtend(ref lp_base, _, LpInterior(InteriorField(_))) => {
                 match lp_base.to_type().sty {
-                    ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor(self.tcx()) => {
+                    ty::TyStruct(def, _) | ty::TyEnum(def, _) if def.has_dtor() => {
                         // In the case where the owner implements drop, then
                         // the path must be initialized to prevent a case of
                         // partial reinitialization
diff --git a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
index 308ae42c16f..2d08183ba6e 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/gather_moves.rs
@@ -180,7 +180,7 @@ fn check_and_get_illegal_move_origin<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         mc::cat_interior(ref b, mc::InteriorElement(Kind::Pattern, _)) => {
             match b.ty.sty {
                 ty::TyStruct(def, _) | ty::TyEnum(def, _) => {
-                    if def.has_dtor(bccx.tcx) {
+                    if def.has_dtor() {
                         Some(cmt.clone())
                     } else {
                         check_and_get_illegal_move_origin(bccx, b)
diff --git a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
index 1246449327d..465fffe3385 100644
--- a/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
+++ b/src/librustc_borrowck/borrowck/gather_loans/move_error.rs
@@ -137,7 +137,7 @@ fn report_cannot_move_out_of<'a, 'tcx>(bccx: &BorrowckCtxt<'a, 'tcx>,
         mc::cat_interior(ref b, mc::InteriorField(_)) => {
             match b.ty.sty {
                 ty::TyStruct(def, _) |
-                ty::TyEnum(def, _) if def.has_dtor(bccx.tcx) => {
+                ty::TyEnum(def, _) if def.has_dtor() => {
                     bccx.span_err(
                         move_from.span,
                         &format!("cannot move out of type `{}`, \
diff --git a/src/librustc_lint/builtin.rs b/src/librustc_lint/builtin.rs
index 7af2b3c1bfc..e582b9266cd 100644
--- a/src/librustc_lint/builtin.rs
+++ b/src/librustc_lint/builtin.rs
@@ -1952,26 +1952,26 @@ impl LintPass for MissingCopyImplementations {
         if !cx.exported_items.contains(&item.id) {
             return;
         }
-        if cx.tcx.destructor_for_type.borrow().contains_key(&DefId::local(item.id)) {
-            return;
-        }
-        let ty = match item.node {
+        let (def, ty) = match item.node {
             ast::ItemStruct(_, ref ast_generics) => {
                 if ast_generics.is_parameterized() {
                     return;
                 }
-                cx.tcx.mk_struct(cx.tcx.lookup_adt_def(DefId::local(item.id)),
-                                 cx.tcx.mk_substs(Substs::empty()))
+                let def = cx.tcx.lookup_adt_def(DefId::local(item.id));
+                (def, cx.tcx.mk_struct(def,
+                                       cx.tcx.mk_substs(Substs::empty())))
             }
             ast::ItemEnum(_, ref ast_generics) => {
                 if ast_generics.is_parameterized() {
                     return;
                 }
-                cx.tcx.mk_enum(cx.tcx.lookup_adt_def(DefId::local(item.id)),
-                               cx.tcx.mk_substs(Substs::empty()))
+                let def = cx.tcx.lookup_adt_def(DefId::local(item.id));
+                (def, cx.tcx.mk_enum(def,
+                                     cx.tcx.mk_substs(Substs::empty())))
             }
             _ => return,
         };
+        if def.has_dtor() { return; }
         let parameter_environment = cx.tcx.empty_parameter_environment();
         // FIXME (@jroesch) should probably inver this so that the parameter env still impls this
         // method
@@ -2583,7 +2583,7 @@ impl LintPass for DropWithReprExtern {
                     let self_type_did = self_type_def.did;
                     let hints = ctx.tcx.lookup_repr_hints(self_type_did);
                     if hints.iter().any(|attr| *attr == attr::ReprExtern) &&
-                        ctx.tcx.ty_dtor(self_type_did).has_drop_flag() {
+                        self_type_def.dtor_kind().has_drop_flag() {
                         let drop_impl_span = ctx.tcx.map.def_id_span(drop_impl_did,
                                                                      codemap::DUMMY_SP);
                         let self_defn_span = ctx.tcx.map.def_id_span(self_type_did,
diff --git a/src/librustc_trans/trans/adt.rs b/src/librustc_trans/trans/adt.rs
index 46211e6bd01..e425ffcaebf 100644
--- a/src/librustc_trans/trans/adt.rs
+++ b/src/librustc_trans/trans/adt.rs
@@ -250,7 +250,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
                 monomorphize::field_ty(cx.tcx(), substs, field)
             }).collect::<Vec<_>>();
             let packed = cx.tcx().lookup_packed(def.did);
-            let dtor = cx.tcx().ty_dtor(def.did).has_drop_flag();
+            let dtor = def.dtor_kind().has_drop_flag();
             if dtor {
                 ftys.push(cx.tcx().dtor_type());
             }
@@ -265,7 +265,7 @@ fn represent_type_uncached<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
             let hint = *cx.tcx().lookup_repr_hints(def.did).get(0)
                 .unwrap_or(&attr::ReprAny);
 
-            let dtor = cx.tcx().ty_dtor(def.did).has_drop_flag();
+            let dtor = def.dtor_kind().has_drop_flag();
 
             if cases.is_empty() {
                 // Uninhabitable; represent as unit
diff --git a/src/librustc_trans/trans/expr.rs b/src/librustc_trans/trans/expr.rs
index efccba91650..64c146e3825 100644
--- a/src/librustc_trans/trans/expr.rs
+++ b/src/librustc_trans/trans/expr.rs
@@ -1267,7 +1267,7 @@ fn trans_def_dps_unadjusted<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
         def::DefStruct(_) => {
             let ty = expr_ty(bcx, ref_expr);
             match ty.sty {
-                ty::TyStruct(def, _) if def.has_dtor(bcx.tcx()) => {
+                ty::TyStruct(def, _) if def.has_dtor() => {
                     let repr = adt::represent_type(bcx.ccx(), ty);
                     adt::trans_set_discr(bcx, &*repr, lldest, 0);
                 }
diff --git a/src/librustc_trans/trans/glue.rs b/src/librustc_trans/trans/glue.rs
index 93b637ecb4f..b72f6bbb451 100644
--- a/src/librustc_trans/trans/glue.rs
+++ b/src/librustc_trans/trans/glue.rs
@@ -16,11 +16,9 @@
 use back::link::*;
 use llvm;
 use llvm::{ValueRef, get_param};
-use metadata::csearch;
-use middle::def_id::{DefId, LOCAL_CRATE};
 use middle::lang_items::ExchangeFreeFnLangItem;
-use middle::subst;
-use middle::subst::{Subst, Substs};
+use middle::subst::{Substs};
+use middle::traits;
 use middle::ty::{self, Ty};
 use trans::adt;
 use trans::adt::GetDtorType; // for tcx.dtor_type()
@@ -33,16 +31,15 @@ use trans::common::*;
 use trans::debuginfo::DebugLoc;
 use trans::declare;
 use trans::expr;
-use trans::foreign;
-use trans::inline;
 use trans::machine::*;
 use trans::monomorphize;
-use trans::type_of::{type_of, type_of_dtor, sizing_type_of, align_of};
+use trans::type_of::{type_of, sizing_type_of, align_of};
 use trans::type_::Type;
 
 use arena::TypedArena;
 use libc::c_uint;
 use syntax::ast;
+use syntax::codemap::DUMMY_SP;
 
 pub fn trans_exchange_free_dyn<'blk, 'tcx>(cx: Block<'blk, 'tcx>,
                                            v: ValueRef,
@@ -287,10 +284,7 @@ fn get_drop_glue_core<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
 
 fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
                                       t: Ty<'tcx>,
-                                      struct_data: ValueRef,
-                                      dtor_did: DefId,
-                                      class_did: DefId,
-                                      substs: &subst::Substs<'tcx>)
+                                      struct_data: ValueRef)
                                       -> Block<'blk, 'tcx> {
     assert!(type_is_sized(bcx.tcx(), t), "Precondition: caller must ensure t is sized");
 
@@ -318,59 +312,19 @@ fn trans_struct_drop_flag<'blk, 'tcx>(mut bcx: Block<'blk, 'tcx>,
 
     let drop_flag_dtor_needed = ICmp(bcx, llvm::IntEQ, loaded, init_val, DebugLoc::None);
     with_cond(bcx, drop_flag_dtor_needed, |cx| {
-        trans_struct_drop(cx, t, struct_data, dtor_did, class_did, substs)
+        trans_struct_drop(cx, t, struct_data)
     })
 }
-
-pub fn get_res_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>,
-                              did: DefId,
-                              parent_id: DefId,
-                              substs: &Substs<'tcx>)
-                              -> ValueRef {
-    let _icx = push_ctxt("trans_res_dtor");
-    let did = inline::maybe_instantiate_inline(ccx, did);
-
-    if !substs.types.is_empty() {
-        assert_eq!(did.krate, LOCAL_CRATE);
-
-        // Since we're in trans we don't care for any region parameters
-        let substs = ccx.tcx().mk_substs(Substs::erased(substs.types.clone()));
-
-        let (val, _, _) = monomorphize::monomorphic_fn(ccx, did, substs, None);
-
-        val
-    } else if did.is_local() {
-        get_item_val(ccx, did.node)
-    } else {
-        let tcx = ccx.tcx();
-        let name = csearch::get_symbol(&ccx.sess().cstore, did);
-        let class_ty = tcx.lookup_item_type(parent_id).ty.subst(tcx, substs);
-        let llty = type_of_dtor(ccx, class_ty);
-        foreign::get_extern_fn(ccx, &mut *ccx.externs().borrow_mut(), &name[..], llvm::CCallConv,
-                               llty, ccx.tcx().mk_nil())
-    }
-}
-
 fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
                                  t: Ty<'tcx>,
-                                 v0: ValueRef,
-                                 dtor_did: DefId,
-                                 class_did: DefId,
-                                 substs: &subst::Substs<'tcx>)
+                                 v0: ValueRef)
                                  -> Block<'blk, 'tcx>
 {
     debug!("trans_struct_drop t: {}", t);
+    let tcx = bcx.tcx();
+    let mut bcx = bcx;
 
-    // Find and call the actual destructor
-    let dtor_addr = get_res_dtor(bcx.ccx(), dtor_did, class_did, substs);
-
-    // Class dtors have no explicit args, so the params should
-    // just consist of the environment (self).
-    let params = unsafe {
-        let ty = Type::from_ref(llvm::LLVMTypeOf(dtor_addr));
-        ty.element_type().func_params()
-    };
-    assert_eq!(params.len(), if type_is_sized(bcx.tcx(), t) { 1 } else { 2 });
+    let def = t.ty_adt_def().unwrap();
 
     // Be sure to put the contents into a scope so we can use an invoke
     // instruction to call the user destructor but still call the field
@@ -384,15 +338,37 @@ fn trans_struct_drop<'blk, 'tcx>(bcx: Block<'blk, 'tcx>,
     // discriminant (if any) in case of variant swap in drop code.
     bcx.fcx.schedule_drop_adt_contents(cleanup::CustomScope(contents_scope), v0, t);
 
-    let glue_type = get_drop_glue_type(bcx.ccx(), t);
-    let dtor_ty = bcx.tcx().mk_ctor_fn(class_did, &[glue_type], bcx.tcx().mk_nil());
-    let (_, bcx) = if type_is_sized(bcx.tcx(), t) {
-        invoke(bcx, dtor_addr, &[v0], dtor_ty, DebugLoc::None)
+    let (sized_args, unsized_args);
+    let args: &[ValueRef] = if type_is_sized(tcx, t) {
+        sized_args = [v0];
+        &sized_args
     } else {
-        let args = [Load(bcx, expr::get_dataptr(bcx, v0)), Load(bcx, expr::get_meta(bcx, v0))];
-        invoke(bcx, dtor_addr, &args, dtor_ty, DebugLoc::None)
+        unsized_args = [Load(bcx, expr::get_dataptr(bcx, v0)), Load(bcx, expr::get_meta(bcx, v0))];
+        &unsized_args
     };
 
+    bcx = callee::trans_call_inner(bcx, DebugLoc::None, |bcx, _| {
+        let trait_ref = ty::Binder(ty::TraitRef {
+            def_id: tcx.lang_items.drop_trait().unwrap(),
+            substs: tcx.mk_substs(Substs::trans_empty().with_self_ty(t))
+        });
+        let vtbl = match fulfill_obligation(bcx.ccx(), DUMMY_SP, trait_ref) {
+            traits::VtableImpl(data) => data,
+            _ => tcx.sess.bug(&format!("dtor for {:?} is not an impl???", t))
+        };
+        let dtor_did = def.destructor().unwrap();
+        let datum = callee::trans_fn_ref_with_substs(bcx.ccx(),
+                                                     dtor_did,
+                                                     ExprId(0),
+                                                     bcx.fcx.param_substs,
+                                                     vtbl.substs);
+        callee::Callee {
+            bcx: bcx,
+            data: callee::Fn(datum.val),
+            ty: datum.ty
+        }
+    }, callee::ArgVals(args), Some(expr::Ignore)).bcx;
+
     bcx.fcx.pop_and_trans_custom_cleanup_scope(bcx, contents_scope)
 }
 
@@ -557,27 +533,26 @@ fn make_drop_glue<'blk, 'tcx>(bcx: Block<'blk, 'tcx>, v0: ValueRef, g: DropGlueK
                 })
             }
         }
-        ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
-            let tcx = bcx.tcx();
-            match (tcx.ty_dtor(def.did), skip_dtor) {
-                (ty::TraitDtor(dtor, true), false) => {
+        ty::TyStruct(def, _) | ty::TyEnum(def, _) => {
+            match (def.dtor_kind(), skip_dtor) {
+                (ty::TraitDtor(true), false) => {
                     // FIXME(16758) Since the struct is unsized, it is hard to
                     // find the drop flag (which is at the end of the struct).
                     // Lets just ignore the flag and pretend everything will be
                     // OK.
                     if type_is_sized(bcx.tcx(), t) {
-                        trans_struct_drop_flag(bcx, t, v0, dtor, def.did, substs)
+                        trans_struct_drop_flag(bcx, t, v0)
                     } else {
                         // Give the user a heads up that we are doing something
                         // stupid and dangerous.
                         bcx.sess().warn(&format!("Ignoring drop flag in destructor for {}\
                                                  because the struct is unsized. See issue\
                                                  #16758", t));
-                        trans_struct_drop(bcx, t, v0, dtor, def.did, substs)
+                        trans_struct_drop(bcx, t, v0)
                     }
                 }
-                (ty::TraitDtor(dtor, false), false) => {
-                    trans_struct_drop(bcx, t, v0, dtor, def.did, substs)
+                (ty::TraitDtor(false), false) => {
+                    trans_struct_drop(bcx, t, v0)
                 }
                 (ty::NoDtor, _) | (_, true) => {
                     // No dtor? Just the default case
diff --git a/src/librustc_trans/trans/type_of.rs b/src/librustc_trans/trans/type_of.rs
index c8ea6e6ec42..171d6961470 100644
--- a/src/librustc_trans/trans/type_of.rs
+++ b/src/librustc_trans/trans/type_of.rs
@@ -487,11 +487,3 @@ fn llvm_type_name<'a, 'tcx>(cx: &CrateContext<'a, 'tcx>,
         format!("{}.{}", did.krate, tstr)
     }
 }
-
-pub fn type_of_dtor<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, self_ty: Ty<'tcx>) -> Type {
-    if type_is_sized(ccx.tcx(), self_ty) {
-        Type::func(&[type_of(ccx, self_ty).ptr_to()], &Type::void(ccx))
-    } else {
-        Type::func(&type_of(ccx, self_ty).field_types(), &Type::void(ccx))
-    }
-}
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index b6a91ce8a64..a8c77f863b7 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -11,9 +11,11 @@
 use check::regionck::{self, Rcx};
 
 use middle::def_id::{DefId, LOCAL_CRATE};
+use middle::free_region::FreeRegionMap;
 use middle::infer;
 use middle::region;
 use middle::subst::{self, Subst};
+use middle::traits;
 use middle::ty::{self, Ty};
 use util::nodemap::FnvHashSet;
 
@@ -75,53 +77,23 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
     drop_impl_ty: &ty::Ty<'tcx>,
     self_type_did: DefId) -> Result<(), ()>
 {
-    // New strategy based on review suggestion from nikomatsakis.
-    //
-    // (In the text and code below, "named" denotes "struct/enum", and
-    // "generic params" denotes "type and region params")
-    //
-    // 1. Create fresh skolemized type/region "constants" for each of
-    //    the named type's generic params.  Instantiate the named type
-    //    with the fresh constants, yielding `named_skolem`.
-    //
-    // 2. Create unification variables for each of the Drop impl's
-    //    generic params.  Instantiate the impl's Self's type with the
-    //    unification-vars, yielding `drop_unifier`.
-    //
-    // 3. Attempt to unify Self_unif with Type_skolem.  If unification
-    //    succeeds, continue (i.e. with the predicate checks).
-
-    let ty::TypeScheme { generics: ref named_type_generics,
-                         ty: named_type } =
-        tcx.lookup_item_type(self_type_did);
-
-    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, None, false);
-
-    infcx.commit_if_ok(|snapshot| {
-        let (named_type_to_skolem, skol_map) =
-            infcx.construct_skolemized_subst(named_type_generics, snapshot);
-        let named_type_skolem = named_type.subst(tcx, &named_type_to_skolem);
-
-        let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
-        let drop_to_unifier =
-            infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
-        let drop_unifier = drop_impl_ty.subst(tcx, &drop_to_unifier);
-
-        if let Ok(()) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span),
-                                       named_type_skolem, drop_unifier) {
-            // Even if we did manage to equate the types, the process
-            // may have just gathered unsolvable region constraints
-            // like `R == 'static` (represented as a pair of subregion
-            // constraints) for some skolemization constant R.
-            //
-            // However, the leak_check method allows us to confirm
-            // that no skolemized regions escaped (i.e. were related
-            // to other regions in the constraint graph).
-            if let Ok(()) = infcx.leak_check(&skol_map, snapshot) {
-                return Ok(())
-            }
-        }
+    assert!(drop_impl_did.is_local() && self_type_did.is_local());
+
+    // check that the impl type can be made to match the trait type.
+
+    let impl_param_env = ty::ParameterEnvironment::for_item(tcx, self_type_did.node);
+    let infcx = infer::new_infer_ctxt(tcx, &tcx.tables, Some(impl_param_env), true);
+
+    let named_type = tcx.lookup_item_type(self_type_did).ty;
+    let named_type = named_type.subst(tcx, &infcx.parameter_environment.free_substs);
 
+    let drop_impl_span = tcx.map.def_id_span(drop_impl_did, codemap::DUMMY_SP);
+    let fresh_impl_substs =
+        infcx.fresh_substs_for_generics(drop_impl_span, drop_impl_generics);
+    let fresh_impl_self_ty = drop_impl_ty.subst(tcx, &fresh_impl_substs);
+
+    if let Err(_) = infer::mk_eqty(&infcx, true, infer::TypeOrigin::Misc(drop_impl_span),
+                                   named_type, fresh_impl_self_ty) {
         span_err!(tcx.sess, drop_impl_span, E0366,
                   "Implementations of Drop cannot be specialized");
         let item_span = tcx.map.span(self_type_did.node);
@@ -129,7 +101,17 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
                            "Use same sequence of generic type and region \
                             parameters that is on the struct/enum definition");
         return Err(());
-    })
+    }
+
+    if let Err(ref errors) = infcx.fulfillment_cx.borrow_mut().select_all_or_error(&infcx) {
+        // this could be reached when we get lazy normalization
+        traits::report_fulfillment_errors(&infcx, errors);
+        return Err(());
+    }
+
+    let free_regions = FreeRegionMap::new();
+    infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_did.node);
+    Ok(())
 }
 
 /// Confirms that every predicate imposed by dtor_predicates is
diff --git a/src/librustc_typeck/coherence/mod.rs b/src/librustc_typeck/coherence/mod.rs
index aadd74708ab..f8778fbc42d 100644
--- a/src/librustc_typeck/coherence/mod.rs
+++ b/src/librustc_typeck/coherence/mod.rs
@@ -311,9 +311,7 @@ impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
             match self_type.ty.sty {
                 ty::TyEnum(type_def, _) |
                 ty::TyStruct(type_def, _) => {
-                    tcx.destructor_for_type
-                       .borrow_mut()
-                       .insert(type_def.did, method_def_id.def_id());
+                    type_def.set_destructor(method_def_id.def_id());
                     tcx.destructors
                        .borrow_mut()
                        .insert(method_def_id.def_id());
diff --git a/src/test/compile-fail/reject-specialized-drops-8142.rs b/src/test/compile-fail/reject-specialized-drops-8142.rs
index 1e189528f18..b12e26fddf6 100644
--- a/src/test/compile-fail/reject-specialized-drops-8142.rs
+++ b/src/test/compile-fail/reject-specialized-drops-8142.rs
@@ -37,7 +37,9 @@ impl<'al,'adds_bnd>     Drop for L<'al,'adds_bnd> where 'adds_bnd:'al {    // RE
 impl<'ml>               Drop for M<'ml>         { fn drop(&mut self) { } } // ACCEPT
 
 impl                    Drop for N<'static>     { fn drop(&mut self) { } } // REJECT
-//~^ ERROR Implementations of Drop cannot be specialized
+//~^ ERROR mismatched types
+//~| expected `N<'n>`
+//~|    found `N<'static>`
 
 impl<Cok_nobound> Drop for O<Cok_nobound> { fn drop(&mut self) { } } // ACCEPT
 
@@ -57,9 +59,9 @@ impl<'t,Bt:'t>    Drop for T<'t,Bt>       { fn drop(&mut self) { } } // ACCEPT
 impl              Drop for U              { fn drop(&mut self) { } } // ACCEPT
 
 impl<One>         Drop for V<One,One>     { fn drop(&mut self) { } } // REJECT
-//~^ERROR Implementations of Drop cannot be specialized
+//~^ ERROR Implementations of Drop cannot be specialized
 
 impl<'lw>         Drop for W<'lw,'lw>     { fn drop(&mut self) { } } // REJECT
-//~^ERROR Implementations of Drop cannot be specialized
+//~^ ERROR cannot infer an appropriate lifetime
 
 pub fn main() { }
diff --git a/src/test/run-pass/issue-27997.rs b/src/test/run-pass/issue-27997.rs
new file mode 100644
index 00000000000..cd81f689693
--- /dev/null
+++ b/src/test/run-pass/issue-27997.rs
@@ -0,0 +1,48 @@
+// Copyright 2015 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.
+
+#![feature(const_fn)]
+
+use std::sync::atomic::{Ordering, AtomicUsize};
+
+use std::mem;
+struct S<U,V> {
+    _u: U,
+    size_of_u: usize,
+    _v: V,
+    size_of_v: usize
+}
+
+impl<U, V> S<U, V> {
+    fn new(u: U, v: V) -> Self {
+        S {
+            _u: u,
+            size_of_u: mem::size_of::<U>(),
+            _v: v,
+            size_of_v: mem::size_of::<V>()
+        }
+    }
+}
+
+static COUNT: AtomicUsize = AtomicUsize::new(0);
+
+impl<V, U> Drop for S<U, V> {
+    fn drop(&mut self) {
+        assert_eq!(mem::size_of::<U>(), self.size_of_u);
+        assert_eq!(mem::size_of::<V>(), self.size_of_v);
+        COUNT.store(COUNT.load(Ordering::SeqCst)+1, Ordering::SeqCst);
+    }
+}
+
+fn main() {
+    assert_eq!(COUNT.load(Ordering::SeqCst), 0);
+    { S::new(0u8, 1u16); }
+    assert_eq!(COUNT.load(Ordering::SeqCst), 1);
+}