diff options
| author | Niko Matsakis <niko@alum.mit.edu> | 2017-05-12 11:44:31 -0400 |
|---|---|---|
| committer | Niko Matsakis <niko@alum.mit.edu> | 2017-05-22 15:37:10 -0400 |
| commit | b46c1a95d0fd309c4d6a8e42da7cc2da034326b9 (patch) | |
| tree | aecbce20b797bc3d8358d3e19f08d52ad776967a | |
| parent | 5a5c265e24cc79a8e28f01930380cb8a2481165c (diff) | |
| download | rust-b46c1a95d0fd309c4d6a8e42da7cc2da034326b9.tar.gz rust-b46c1a95d0fd309c4d6a8e42da7cc2da034326b9.zip | |
move `needs_drop` into a query
| -rw-r--r-- | src/librustc/dep_graph/dep_node.rs | 2 | ||||
| -rw-r--r-- | src/librustc/ty/maps.rs | 12 | ||||
| -rw-r--r-- | src/librustc/ty/util.rs | 178 |
3 files changed, 86 insertions, 106 deletions
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs index 2620a9c8f2d..12a3e5bfaa0 100644 --- a/src/librustc/dep_graph/dep_node.rs +++ b/src/librustc/dep_graph/dep_node.rs @@ -111,6 +111,7 @@ pub enum DepNode<D: Clone + Debug> { IsCopy(D), IsSized(D), IsFreeze(D), + NeedsDrop(D), // The set of impls for a given trait. Ultimately, it would be // nice to get more fine-grained here (e.g., to include a @@ -240,6 +241,7 @@ impl<D: Clone + Debug> DepNode<D> { IsCopy(ref d) => op(d).map(IsCopy), IsSized(ref d) => op(d).map(IsSized), IsFreeze(ref d) => op(d).map(IsFreeze), + NeedsDrop(ref d) => op(d).map(NeedsDrop), Hir(ref d) => op(d).map(Hir), HirBody(ref d) => op(d).map(HirBody), MetaData(ref d) => op(d).map(MetaData), diff --git a/src/librustc/ty/maps.rs b/src/librustc/ty/maps.rs index 2c3dae8493a..5f2bc03ed9e 100644 --- a/src/librustc/ty/maps.rs +++ b/src/librustc/ty/maps.rs @@ -271,6 +271,12 @@ impl<'tcx> QueryDescription for queries::is_freeze_raw<'tcx> { } } +impl<'tcx> QueryDescription for queries::needs_drop_raw<'tcx> { + fn describe(_tcx: TyCtxt, env: ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> String { + format!("computing whether `{}` needs drop", env.value) + } +} + impl<'tcx> QueryDescription for queries::super_predicates_of<'tcx> { fn describe(tcx: TyCtxt, def_id: DefId) -> String { format!("computing the supertraits of `{}`", @@ -891,6 +897,7 @@ define_maps! { <'tcx> [] is_copy_raw: is_copy_dep_node(ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> bool, [] is_sized_raw: is_sized_dep_node(ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> bool, [] is_freeze_raw: is_freeze_dep_node(ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> bool, + [] needs_drop_raw: needs_drop_dep_node(ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> bool, } fn coherent_trait_dep_node((_, def_id): (CrateNum, DefId)) -> DepNode<DefId> { @@ -949,3 +956,8 @@ fn is_freeze_dep_node<'tcx>(_: ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> D let krate_def_id = DefId::local(CRATE_DEF_INDEX); DepNode::IsSized(krate_def_id) } + +fn needs_drop_dep_node<'tcx>(_: ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) -> DepNode<DefId> { + let krate_def_id = DefId::local(CRATE_DEF_INDEX); + DepNode::NeedsDrop(krate_def_id) +} diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs index da2552d37e2..0c2f4efccd5 100644 --- a/src/librustc/ty/util.rs +++ b/src/librustc/ty/util.rs @@ -15,14 +15,13 @@ use hir::map::DefPathData; use infer::InferCtxt; use ich::{StableHashingContext, NodeIdHashingMode}; use traits::{self, Reveal}; -use ty::{self, Ty, TyCtxt, TypeFlags, TypeFoldable}; +use ty::{self, Ty, TyCtxt, TypeFoldable}; use ty::ParameterEnvironment; use ty::fold::TypeVisitor; use ty::layout::{Layout, LayoutError}; use ty::subst::{Subst, Kind}; use ty::TypeVariants::*; use util::common::ErrorReported; -use util::nodemap::FxHashSet; use middle::lang_items; use rustc_const_math::{ConstInt, ConstIsize, ConstUsize}; @@ -754,110 +753,7 @@ impl<'a, 'tcx> ty::TyS<'tcx> { tcx: TyCtxt<'a, 'tcx, 'tcx>, param_env: ty::ParameterEnvironment<'tcx>) -> bool { - if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) { - return self.flags.get().intersects(TypeFlags::NEEDS_DROP); - } - - self.needs_drop_uncached(tcx, param_env, &mut FxHashSet()) - } - - fn needs_drop_inner(&'tcx self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParameterEnvironment<'tcx>, - stack: &mut FxHashSet<Ty<'tcx>>) - -> bool { - if self.flags.get().intersects(TypeFlags::NEEDS_DROP_CACHED) { - return self.flags.get().intersects(TypeFlags::NEEDS_DROP); - } - - // This should be reported as an error by `check_representable`. - // - // Consider the type as not needing drop in the meanwhile to avoid - // further errors. - if let Some(_) = stack.replace(self) { - return false; - } - - let needs_drop = self.needs_drop_uncached(tcx, param_env, stack); - - // "Pop" the cycle detection "stack". - stack.remove(self); - - needs_drop - } - - fn needs_drop_uncached(&'tcx self, - tcx: TyCtxt<'a, 'tcx, 'tcx>, - param_env: ty::ParameterEnvironment<'tcx>, - stack: &mut FxHashSet<Ty<'tcx>>) - -> bool { - assert!(!self.needs_infer()); - - let result = match self.sty { - // Fast-path for primitive types - ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | - ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | - ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | - ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false, - - // Issue #22536: We first query type_moves_by_default. It sees a - // normalized version of the type, and therefore will definitely - // know whether the type implements Copy (and thus needs no - // cleanup/drop/zeroing) ... - _ if !self.moves_by_default(tcx, param_env, DUMMY_SP) => false, - - // ... (issue #22536 continued) but as an optimization, still use - // prior logic of asking for the structural "may drop". - - // FIXME(#22815): Note that this is a conservative heuristic; - // it may report that the type "may drop" when actual type does - // not actually have a destructor associated with it. But since - // the type absolutely did not have the `Copy` bound attached - // (see above), it is sound to treat it as having a destructor. - - // User destructors are the only way to have concrete drop types. - ty::TyAdt(def, _) if def.has_dtor(tcx) => true, - - // Can refer to a type which may drop. - // FIXME(eddyb) check this against a ParameterEnvironment. - ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) | - ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true, - - // Structural recursion. - ty::TyArray(ty, _) | ty::TySlice(ty) => { - ty.needs_drop_inner(tcx, param_env, stack) - } - - ty::TyClosure(def_id, ref substs) => { - substs.upvar_tys(def_id, tcx) - .any(|ty| ty.needs_drop_inner(tcx, param_env, stack)) - } - - ty::TyTuple(ref tys, _) => { - tys.iter().any(|ty| ty.needs_drop_inner(tcx, param_env, stack)) - } - - // unions don't have destructors regardless of the child types - ty::TyAdt(def, _) if def.is_union() => false, - - ty::TyAdt(def, substs) => { - def.variants.iter().any(|v| { - v.fields.iter().any(|f| { - f.ty(tcx, substs).needs_drop_inner(tcx, param_env, stack) - }) - }) - } - }; - - if !self.has_param_types() && !self.has_self_ty() { - self.flags.set(self.flags.get() | if result { - TypeFlags::NEEDS_DROP_CACHED | TypeFlags::NEEDS_DROP - } else { - TypeFlags::NEEDS_DROP_CACHED - }); - } - - result + tcx.needs_drop_raw(param_env.and(self)) } #[inline] @@ -1075,11 +971,81 @@ fn is_freeze_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, .enter(|infcx| traits::type_known_to_meet_bound(&infcx, ty, trait_def_id, DUMMY_SP)) } +fn needs_drop_raw<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, + query: ty::ParameterEnvironmentAnd<'tcx, Ty<'tcx>>) + -> bool +{ + let (param_env, ty) = query.into_parts(); + + let needs_drop = |ty: Ty<'tcx>| -> bool { + match ty::queries::needs_drop_raw::try_get(tcx, DUMMY_SP, param_env.and(ty)) { + Ok(v) => v, + Err(_) => { + // Cycles should be reported as an error by `check_representable`. + // + // Consider the type as not needing drop in the meanwhile to avoid + // further errors. + false + } + } + }; + + assert!(!ty.needs_infer()); + + match ty.sty { + // Fast-path for primitive types + ty::TyInfer(ty::FreshIntTy(_)) | ty::TyInfer(ty::FreshFloatTy(_)) | + ty::TyBool | ty::TyInt(_) | ty::TyUint(_) | ty::TyFloat(_) | ty::TyNever | + ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar | + ty::TyRawPtr(_) | ty::TyRef(..) | ty::TyStr => false, + + // Issue #22536: We first query type_moves_by_default. It sees a + // normalized version of the type, and therefore will definitely + // know whether the type implements Copy (and thus needs no + // cleanup/drop/zeroing) ... + _ if !ty.moves_by_default(tcx, param_env, DUMMY_SP) => false, + + // ... (issue #22536 continued) but as an optimization, still use + // prior logic of asking for the structural "may drop". + + // FIXME(#22815): Note that this is a conservative heuristic; + // it may report that the type "may drop" when actual type does + // not actually have a destructor associated with it. But since + // the type absolutely did not have the `Copy` bound attached + // (see above), it is sound to treat it as having a destructor. + + // User destructors are the only way to have concrete drop types. + ty::TyAdt(def, _) if def.has_dtor(tcx) => true, + + // Can refer to a type which may drop. + // FIXME(eddyb) check this against a ParameterEnvironment. + ty::TyDynamic(..) | ty::TyProjection(..) | ty::TyParam(_) | + ty::TyAnon(..) | ty::TyInfer(_) | ty::TyError => true, + + // Structural recursion. + ty::TyArray(ty, _) | ty::TySlice(ty) => needs_drop(ty), + + ty::TyClosure(def_id, ref substs) => substs.upvar_tys(def_id, tcx).any(needs_drop), + + ty::TyTuple(ref tys, _) => tys.iter().cloned().any(needs_drop), + + // unions don't have destructors regardless of the child types + ty::TyAdt(def, _) if def.is_union() => false, + + ty::TyAdt(def, substs) => + def.variants.iter().any( + |variant| variant.fields.iter().any( + |field| needs_drop(field.ty(tcx, substs)))), + } +} + + pub fn provide(providers: &mut ty::maps::Providers) { *providers = ty::maps::Providers { is_copy_raw, is_sized_raw, is_freeze_raw, + needs_drop_raw, ..*providers }; } |
