Skip to content

Commit a1912f2

Browse files
committedFeb 12, 2020
Auto merge of #68679 - matthewjasper:needs-type-op, r=varkor
Improve `ty.needs_drop` * Handle cycles in `needs_drop` correctly * Normalize types when computing `needs_drop` * Move queries from rustc to rustc_ty * Avoid query in simple cases reopens #65918
2 parents 2d2be57 + 30a8353 commit a1912f2

File tree

16 files changed

+337
-163
lines changed

16 files changed

+337
-163
lines changed
 

‎src/librustc/query/mod.rs

+11-8
Original file line numberDiff line numberDiff line change
@@ -669,26 +669,29 @@ rustc_queries! {
669669
no_force
670670
desc { "computing whether `{}` is `Copy`", env.value }
671671
}
672+
/// Query backing `TyS::is_sized`.
672673
query is_sized_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
673674
no_force
674675
desc { "computing whether `{}` is `Sized`", env.value }
675676
}
677+
/// Query backing `TyS::is_freeze`.
676678
query is_freeze_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
677679
no_force
678680
desc { "computing whether `{}` is freeze", env.value }
679681
}
680-
681-
// The cycle error here should be reported as an error by `check_representable`.
682-
// We consider the type as not needing drop in the meanwhile to avoid
683-
// further errors (done in impl Value for NeedsDrop).
684-
// Use `cycle_delay_bug` to delay the cycle error here to be emitted later
685-
// in case we accidentally otherwise don't emit an error.
686-
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop {
687-
cycle_delay_bug
682+
/// Query backing `TyS::needs_drop`.
683+
query needs_drop_raw(env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
688684
no_force
689685
desc { "computing whether `{}` needs drop", env.value }
690686
}
691687

688+
/// A list of types where the ADT requires drop if and only if any of
689+
/// those types require drop. If the ADT is known to always need drop
690+
/// then `Err(AlwaysRequiresDrop)` is returned.
691+
query adt_drop_tys(_: DefId) -> Result<&'tcx ty::List<Ty<'tcx>>, AlwaysRequiresDrop> {
692+
cache_on_disk_if { true }
693+
}
694+
692695
query layout_raw(
693696
env: ty::ParamEnvAnd<'tcx, Ty<'tcx>>
694697
) -> Result<&'tcx ty::layout::LayoutDetails, ty::layout::LayoutError<'tcx>> {

‎src/librustc/traits/misc.rs

-132
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,9 @@
11
//! Miscellaneous type-system utilities that are too small to deserve their own modules.
22
3-
use crate::middle::lang_items;
43
use crate::traits::{self, ObligationCause};
5-
use crate::ty::util::NeedsDrop;
64
use crate::ty::{self, Ty, TyCtxt, TypeFoldable};
75

86
use rustc_hir as hir;
9-
use rustc_span::DUMMY_SP;
107

118
#[derive(Clone)]
129
pub enum CopyImplementationError<'tcx> {
@@ -71,132 +68,3 @@ pub fn can_type_implement_copy(
7168
Ok(())
7269
})
7370
}
74-
75-
fn is_copy_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
76-
is_item_raw(tcx, query, lang_items::CopyTraitLangItem)
77-
}
78-
79-
fn is_sized_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
80-
is_item_raw(tcx, query, lang_items::SizedTraitLangItem)
81-
}
82-
83-
fn is_freeze_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> bool {
84-
is_item_raw(tcx, query, lang_items::FreezeTraitLangItem)
85-
}
86-
87-
fn is_item_raw<'tcx>(
88-
tcx: TyCtxt<'tcx>,
89-
query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>,
90-
item: lang_items::LangItem,
91-
) -> bool {
92-
let (param_env, ty) = query.into_parts();
93-
let trait_def_id = tcx.require_lang_item(item, None);
94-
tcx.infer_ctxt().enter(|infcx| {
95-
traits::type_known_to_meet_bound_modulo_regions(
96-
&infcx,
97-
param_env,
98-
ty,
99-
trait_def_id,
100-
DUMMY_SP,
101-
)
102-
})
103-
}
104-
105-
fn needs_drop_raw<'tcx>(tcx: TyCtxt<'tcx>, query: ty::ParamEnvAnd<'tcx, Ty<'tcx>>) -> NeedsDrop {
106-
let (param_env, ty) = query.into_parts();
107-
108-
let needs_drop = |ty: Ty<'tcx>| -> bool { tcx.needs_drop_raw(param_env.and(ty)).0 };
109-
110-
assert!(!ty.needs_infer());
111-
112-
NeedsDrop(match ty.kind {
113-
// Fast-path for primitive types
114-
ty::Infer(ty::FreshIntTy(_))
115-
| ty::Infer(ty::FreshFloatTy(_))
116-
| ty::Bool
117-
| ty::Int(_)
118-
| ty::Uint(_)
119-
| ty::Float(_)
120-
| ty::Never
121-
| ty::FnDef(..)
122-
| ty::FnPtr(_)
123-
| ty::Char
124-
| ty::GeneratorWitness(..)
125-
| ty::RawPtr(_)
126-
| ty::Ref(..)
127-
| ty::Str => false,
128-
129-
// Foreign types can never have destructors
130-
ty::Foreign(..) => false,
131-
132-
// `ManuallyDrop` doesn't have a destructor regardless of field types.
133-
ty::Adt(def, _) if Some(def.did) == tcx.lang_items().manually_drop() => false,
134-
135-
// Issue #22536: We first query `is_copy_modulo_regions`. It sees a
136-
// normalized version of the type, and therefore will definitely
137-
// know whether the type implements Copy (and thus needs no
138-
// cleanup/drop/zeroing) ...
139-
_ if ty.is_copy_modulo_regions(tcx, param_env, DUMMY_SP) => false,
140-
141-
// ... (issue #22536 continued) but as an optimization, still use
142-
// prior logic of asking for the structural "may drop".
143-
144-
// FIXME(#22815): Note that this is a conservative heuristic;
145-
// it may report that the type "may drop" when actual type does
146-
// not actually have a destructor associated with it. But since
147-
// the type absolutely did not have the `Copy` bound attached
148-
// (see above), it is sound to treat it as having a destructor.
149-
150-
// User destructors are the only way to have concrete drop types.
151-
ty::Adt(def, _) if def.has_dtor(tcx) => true,
152-
153-
// Can refer to a type which may drop.
154-
// FIXME(eddyb) check this against a ParamEnv.
155-
ty::Dynamic(..)
156-
| ty::Projection(..)
157-
| ty::Param(_)
158-
| ty::Bound(..)
159-
| ty::Placeholder(..)
160-
| ty::Opaque(..)
161-
| ty::Infer(_)
162-
| ty::Error => true,
163-
164-
ty::UnnormalizedProjection(..) => bug!("only used with chalk-engine"),
165-
166-
// Zero-length arrays never contain anything to drop.
167-
ty::Array(_, len) if len.try_eval_usize(tcx, param_env) == Some(0) => false,
168-
169-
// Structural recursion.
170-
ty::Array(ty, _) | ty::Slice(ty) => needs_drop(ty),
171-
172-
ty::Closure(def_id, ref substs) => {
173-
substs.as_closure().upvar_tys(def_id, tcx).any(needs_drop)
174-
}
175-
176-
// Pessimistically assume that all generators will require destructors
177-
// as we don't know if a destructor is a noop or not until after the MIR
178-
// state transformation pass
179-
ty::Generator(..) => true,
180-
181-
ty::Tuple(..) => ty.tuple_fields().any(needs_drop),
182-
183-
// unions don't have destructors because of the child types,
184-
// only if they manually implement `Drop` (handled above).
185-
ty::Adt(def, _) if def.is_union() => false,
186-
187-
ty::Adt(def, substs) => def
188-
.variants
189-
.iter()
190-
.any(|variant| variant.fields.iter().any(|field| needs_drop(field.ty(tcx, substs)))),
191-
})
192-
}
193-
194-
pub fn provide(providers: &mut ty::query::Providers<'_>) {
195-
*providers = ty::query::Providers {
196-
is_copy_raw,
197-
is_sized_raw,
198-
is_freeze_raw,
199-
needs_drop_raw,
200-
..*providers
201-
};
202-
}

‎src/librustc/traits/mod.rs

-1
Original file line numberDiff line numberDiff line change
@@ -633,7 +633,6 @@ impl<'tcx> TraitObligation<'tcx> {
633633
}
634634

635635
pub fn provide(providers: &mut ty::query::Providers<'_>) {
636-
misc::provide(providers);
637636
*providers = ty::query::Providers {
638637
is_object_safe: object_safety::is_object_safe_provider,
639638
specialization_graph_of: specialize::specialization_graph_provider,

‎src/librustc/ty/instance.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -285,7 +285,7 @@ impl<'tcx> Instance<'tcx> {
285285
_ => {
286286
if Some(def_id) == tcx.lang_items().drop_in_place_fn() {
287287
let ty = substs.type_at(0);
288-
if ty.needs_drop(tcx, ty::ParamEnv::reveal_all()) {
288+
if ty.needs_drop(tcx, param_env.with_reveal_all()) {
289289
debug!(" => nontrivial drop glue");
290290
ty::InstanceDef::DropGlue(def_id, Some(ty))
291291
} else {

‎src/librustc/ty/mod.rs

+17-5
Original file line numberDiff line numberDiff line change
@@ -1796,19 +1796,22 @@ bitflags! {
17961796
const IS_STRUCT = 1 << 2;
17971797
/// Indicates whether the ADT is a struct and has a constructor.
17981798
const HAS_CTOR = 1 << 3;
1799-
/// Indicates whether the type is a `PhantomData`.
1799+
/// Indicates whether the type is `PhantomData`.
18001800
const IS_PHANTOM_DATA = 1 << 4;
18011801
/// Indicates whether the type has a `#[fundamental]` attribute.
18021802
const IS_FUNDAMENTAL = 1 << 5;
1803-
/// Indicates whether the type is a `Box`.
1803+
/// Indicates whether the type is `Box`.
18041804
const IS_BOX = 1 << 6;
1805+
/// Indicates whether the type is `ManuallyDrop`.
1806+
const IS_MANUALLY_DROP = 1 << 7;
1807+
// FIXME(matthewjasper) replace these with diagnostic items
18051808
/// Indicates whether the type is an `Arc`.
1806-
const IS_ARC = 1 << 7;
1809+
const IS_ARC = 1 << 8;
18071810
/// Indicates whether the type is an `Rc`.
1808-
const IS_RC = 1 << 8;
1811+
const IS_RC = 1 << 9;
18091812
/// Indicates whether the variant list of this ADT is `#[non_exhaustive]`.
18101813
/// (i.e., this flag is never set unless this ADT is an enum).
1811-
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 9;
1814+
const IS_VARIANT_LIST_NON_EXHAUSTIVE = 1 << 10;
18121815
}
18131816
}
18141817

@@ -2190,6 +2193,9 @@ impl<'tcx> AdtDef {
21902193
if Some(did) == tcx.lang_items().owned_box() {
21912194
flags |= AdtFlags::IS_BOX;
21922195
}
2196+
if Some(did) == tcx.lang_items().manually_drop() {
2197+
flags |= AdtFlags::IS_MANUALLY_DROP;
2198+
}
21932199
if Some(did) == tcx.lang_items().arc() {
21942200
flags |= AdtFlags::IS_ARC;
21952201
}
@@ -2290,6 +2296,12 @@ impl<'tcx> AdtDef {
22902296
self.flags.contains(AdtFlags::IS_BOX)
22912297
}
22922298

2299+
/// Returns `true` if this is `ManuallyDrop<T>`.
2300+
#[inline]
2301+
pub fn is_manually_drop(&self) -> bool {
2302+
self.flags.contains(AdtFlags::IS_MANUALLY_DROP)
2303+
}
2304+
22932305
/// Returns `true` if this type has a destructor.
22942306
pub fn has_dtor(&self, tcx: TyCtxt<'tcx>) -> bool {
22952307
self.destructor(tcx).is_some()

‎src/librustc/ty/query/mod.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -33,7 +33,7 @@ use crate::traits::Clauses;
3333
use crate::traits::{self, Vtable};
3434
use crate::ty::steal::Steal;
3535
use crate::ty::subst::SubstsRef;
36-
use crate::ty::util::NeedsDrop;
36+
use crate::ty::util::AlwaysRequiresDrop;
3737
use crate::ty::{self, AdtSizedConstraint, CrateInherentImpls, ParamEnvAnd, Ty, TyCtxt};
3838
use crate::util::common::ErrorReported;
3939
use rustc_data_structures::fingerprint::Fingerprint;

‎src/librustc/ty/query/values.rs

-7
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,3 @@
1-
use crate::ty::util::NeedsDrop;
21
use crate::ty::{self, AdtSizedConstraint, Ty, TyCtxt};
32

43
use rustc_span::symbol::Symbol;
@@ -26,12 +25,6 @@ impl<'tcx> Value<'tcx> for ty::SymbolName {
2625
}
2726
}
2827

29-
impl<'tcx> Value<'tcx> for NeedsDrop {
30-
fn from_cycle_error(_: TyCtxt<'tcx>) -> Self {
31-
NeedsDrop(false)
32-
}
33-
}
34-
3528
impl<'tcx> Value<'tcx> for AdtSizedConstraint<'tcx> {
3629
fn from_cycle_error(tcx: TyCtxt<'tcx>) -> Self {
3730
AdtSizedConstraint(tcx.intern_type_list(&[tcx.types.err]))

‎src/librustc/ty/util.rs

+88-4
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ use rustc_hir::def::DefKind;
1818
use rustc_hir::def_id::DefId;
1919
use rustc_macros::HashStable;
2020
use rustc_span::Span;
21+
use rustc_target::abi::TargetDataLayout;
22+
use smallvec::SmallVec;
2123
use std::{cmp, fmt};
2224
use syntax::ast;
2325

@@ -724,7 +726,23 @@ impl<'tcx> ty::TyS<'tcx> {
724726
/// Note that this method is used to check eligible types in unions.
725727
#[inline]
726728
pub fn needs_drop(&'tcx self, tcx: TyCtxt<'tcx>, param_env: ty::ParamEnv<'tcx>) -> bool {
727-
tcx.needs_drop_raw(param_env.and(self)).0
729+
// Avoid querying in simple cases.
730+
match needs_drop_components(self, &tcx.data_layout) {
731+
Err(AlwaysRequiresDrop) => true,
732+
Ok(components) => {
733+
let query_ty = match *components {
734+
[] => return false,
735+
// If we've got a single component, call the query with that
736+
// to increase the chance that we hit the query cache.
737+
[component_ty] => component_ty,
738+
_ => self,
739+
};
740+
// This doesn't depend on regions, so try to minimize distinct
741+
// query keys used.
742+
let erased = tcx.normalize_erasing_regions(param_env, query_ty);
743+
tcx.needs_drop_raw(param_env.and(erased))
744+
}
745+
}
728746
}
729747

730748
pub fn same_type(a: Ty<'tcx>, b: Ty<'tcx>) -> bool {
@@ -923,9 +941,6 @@ impl<'tcx> ty::TyS<'tcx> {
923941
}
924942
}
925943

926-
#[derive(Clone, HashStable)]
927-
pub struct NeedsDrop(pub bool);
928-
929944
pub enum ExplicitSelf<'tcx> {
930945
ByValue,
931946
ByReference(ty::Region<'tcx>, hir::Mutability),
@@ -974,3 +989,72 @@ impl<'tcx> ExplicitSelf<'tcx> {
974989
}
975990
}
976991
}
992+
993+
/// Returns a list of types such that the given type needs drop if and only if
994+
/// *any* of the returned types need drop. Returns `Err(AlwaysRequiresDrop)` if
995+
/// this type always needs drop.
996+
pub fn needs_drop_components(
997+
ty: Ty<'tcx>,
998+
target_layout: &TargetDataLayout,
999+
) -> Result<SmallVec<[Ty<'tcx>; 2]>, AlwaysRequiresDrop> {
1000+
match ty.kind {
1001+
ty::Infer(ty::FreshIntTy(_))
1002+
| ty::Infer(ty::FreshFloatTy(_))
1003+
| ty::Bool
1004+
| ty::Int(_)
1005+
| ty::Uint(_)
1006+
| ty::Float(_)
1007+
| ty::Never
1008+
| ty::FnDef(..)
1009+
| ty::FnPtr(_)
1010+
| ty::Char
1011+
| ty::GeneratorWitness(..)
1012+
| ty::RawPtr(_)
1013+
| ty::Ref(..)
1014+
| ty::Str => Ok(SmallVec::new()),
1015+
1016+
// Foreign types can never have destructors.
1017+
ty::Foreign(..) => Ok(SmallVec::new()),
1018+
1019+
// Pessimistically assume that all generators will require destructors
1020+
// as we don't know if a destructor is a noop or not until after the MIR
1021+
// state transformation pass.
1022+
ty::Generator(..) | ty::Dynamic(..) | ty::Error => Err(AlwaysRequiresDrop),
1023+
1024+
ty::Slice(ty) => needs_drop_components(ty, target_layout),
1025+
ty::Array(elem_ty, size) => {
1026+
match needs_drop_components(elem_ty, target_layout) {
1027+
Ok(v) if v.is_empty() => Ok(v),
1028+
res => match size.val.try_to_bits(target_layout.pointer_size) {
1029+
// Arrays of size zero don't need drop, even if their element
1030+
// type does.
1031+
Some(0) => Ok(SmallVec::new()),
1032+
Some(_) => res,
1033+
// We don't know which of the cases above we are in, so
1034+
// return the whole type and let the caller decide what to
1035+
// do.
1036+
None => Ok(smallvec![ty]),
1037+
},
1038+
}
1039+
}
1040+
// If any field needs drop, then the whole tuple does.
1041+
ty::Tuple(..) => ty.tuple_fields().try_fold(SmallVec::new(), move |mut acc, elem| {
1042+
acc.extend(needs_drop_components(elem, target_layout)?);
1043+
Ok(acc)
1044+
}),
1045+
1046+
// These require checking for `Copy` bounds or `Adt` destructors.
1047+
ty::Adt(..)
1048+
| ty::Projection(..)
1049+
| ty::UnnormalizedProjection(..)
1050+
| ty::Param(_)
1051+
| ty::Bound(..)
1052+
| ty::Placeholder(..)
1053+
| ty::Opaque(..)
1054+
| ty::Infer(_)
1055+
| ty::Closure(..) => Ok(smallvec![ty]),
1056+
}
1057+
}
1058+
1059+
#[derive(Copy, Clone, Debug, HashStable, RustcEncodable, RustcDecodable)]
1060+
pub struct AlwaysRequiresDrop;

0 commit comments

Comments
 (0)
Please sign in to comment.