diff options
Diffstat (limited to 'src')
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); +} |
