Skip to content

Commit 2bd4b5c

Browse files
committed
Auto merge of #41485 - arielb1:dtorck-constraint, r=eddyb
cache dtorck constraints on ADTs This avoids visiting the fields of all structs multiple times, improving item-bodies checking time by 10% (!). Not sure whether we want this in 1.18 or 1.19. It's a big-ish patch, but the 10% win is very tempting. r? @eddyb
2 parents 23de823 + d3476f4 commit 2bd4b5c

File tree

9 files changed

+320
-447
lines changed

9 files changed

+320
-447
lines changed

src/librustc/dep_graph/dep_node.rs

+2
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,7 @@ pub enum DepNode<D: Clone + Debug> {
9191
IsForeignItem(D),
9292
TypeParamPredicates((D, D)),
9393
SizedConstraint(D),
94+
DtorckConstraint(D),
9495
AdtDestructor(D),
9596
AssociatedItemDefIds(D),
9697
InherentImpls(D),
@@ -228,6 +229,7 @@ impl<D: Clone + Debug> DepNode<D> {
228229
Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
229230
}
230231
SizedConstraint(ref d) => op(d).map(SizedConstraint),
232+
DtorckConstraint(ref d) => op(d).map(DtorckConstraint),
231233
AdtDestructor(ref d) => op(d).map(AdtDestructor),
232234
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
233235
InherentImpls(ref d) => op(d).map(InherentImpls),

src/librustc/diagnostics.rs

+1
Original file line numberDiff line numberDiff line change
@@ -1829,6 +1829,7 @@ register_diagnostics! {
18291829
E0314, // closure outlives stack frame
18301830
E0315, // cannot invoke closure outside of its lifetime
18311831
E0316, // nested quantification of lifetimes
1832+
E0320, // recursive overflow during dropck
18321833
E0473, // dereference of reference outside its lifetime
18331834
E0474, // captured variable `..` does not outlive the enclosing closure
18341835
E0475, // index of slice outside its lifetime

src/librustc/traits/select.rs

+3-5
Original file line numberDiff line numberDiff line change
@@ -1790,11 +1790,9 @@ impl<'cx, 'gcx, 'tcx> SelectionContext<'cx, 'gcx, 'tcx> {
17901790
ty::TyAdt(def, substs) => {
17911791
let sized_crit = def.sized_constraint(self.tcx());
17921792
// (*) binder moved here
1793-
Where(ty::Binder(match sized_crit.sty {
1794-
ty::TyTuple(tys, _) => tys.to_vec().subst(self.tcx(), substs),
1795-
ty::TyBool => vec![],
1796-
_ => vec![sized_crit.subst(self.tcx(), substs)]
1797-
}))
1793+
Where(ty::Binder(
1794+
sized_crit.iter().map(|ty| ty.subst(self.tcx(), substs)).collect()
1795+
))
17981796
}
17991797

18001798
ty::TyProjection(_) | ty::TyParam(_) | ty::TyAnon(..) => None,

src/librustc/ty/maps.rs

+9-1
Original file line numberDiff line numberDiff line change
@@ -107,6 +107,13 @@ impl<'tcx> Value<'tcx> for Ty<'tcx> {
107107
}
108108
}
109109

110+
111+
impl<'tcx> Value<'tcx> for ty::DtorckConstraint<'tcx> {
112+
fn from_cycle_error<'a>(_: TyCtxt<'a, 'tcx, 'tcx>) -> Self {
113+
Self::empty()
114+
}
115+
}
116+
110117
pub struct CycleError<'a, 'tcx: 'a> {
111118
span: Span,
112119
cycle: RefMut<'a, [(Span, Query<'tcx>)]>,
@@ -396,7 +403,8 @@ define_maps! { <'tcx>
396403
pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
397404
pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
398405
pub adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
399-
pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>,
406+
pub adt_sized_constraint: SizedConstraint(DefId) -> &'tcx [Ty<'tcx>],
407+
pub adt_dtorck_constraint: DtorckConstraint(DefId) -> ty::DtorckConstraint<'tcx>,
400408

401409
/// True if this is a foreign item (i.e., linked via `extern { ... }`).
402410
pub is_foreign_item: IsForeignItem(DefId) -> bool,

src/librustc/ty/mod.rs

+97-63
Original file line numberDiff line numberDiff line change
@@ -31,13 +31,15 @@ use ty;
3131
use ty::subst::{Subst, Substs};
3232
use ty::util::IntTypeExt;
3333
use ty::walk::TypeWalker;
34-
use util::nodemap::{NodeSet, DefIdMap, FxHashMap};
34+
use util::common::ErrorReported;
35+
use util::nodemap::{NodeSet, DefIdMap, FxHashMap, FxHashSet};
3536

3637
use serialize::{self, Encodable, Encoder};
3738
use std::cell::{Cell, RefCell, Ref};
3839
use std::collections::BTreeMap;
3940
use std::cmp;
4041
use std::hash::{Hash, Hasher};
42+
use std::iter::FromIterator;
4143
use std::ops::Deref;
4244
use std::rc::Rc;
4345
use std::slice;
@@ -1332,17 +1334,6 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
13321334
pub struct Destructor {
13331335
/// The def-id of the destructor method
13341336
pub did: DefId,
1335-
/// Invoking the destructor of a dtorck type during usual cleanup
1336-
/// (e.g. the glue emitted for stack unwinding) requires all
1337-
/// lifetimes in the type-structure of `adt` to strictly outlive
1338-
/// the adt value itself.
1339-
///
1340-
/// If `adt` is not dtorck, then the adt's destructor can be
1341-
/// invoked even when there are lifetimes in the type-structure of
1342-
/// `adt` that do not strictly outlive the adt value itself.
1343-
/// (This allows programs to make cyclic structures without
1344-
/// resorting to unsafe means; see RFCs 769 and 1238).
1345-
pub is_dtorck: bool,
13461337
}
13471338

13481339
bitflags! {
@@ -1609,14 +1600,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
16091600
}
16101601
}
16111602

1612-
/// Returns whether this is a dtorck type. If this returns
1613-
/// true, this type being safe for destruction requires it to be
1614-
/// alive; Otherwise, only the contents are required to be.
1615-
#[inline]
1616-
pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool {
1617-
self.destructor(tcx).map_or(false, |d| d.is_dtorck)
1618-
}
1619-
16201603
/// Returns whether this type is #[fundamental] for the purposes
16211604
/// of coherence checking.
16221605
#[inline]
@@ -1780,33 +1763,26 @@ impl<'a, 'gcx, 'tcx> AdtDef {
17801763
queries::adt_destructor::get(tcx, DUMMY_SP, self.did)
17811764
}
17821765

1783-
/// Returns a simpler type such that `Self: Sized` if and only
1766+
/// Returns a list of types such that `Self: Sized` if and only
17841767
/// if that type is Sized, or `TyErr` if this type is recursive.
17851768
///
1786-
/// HACK: instead of returning a list of types, this function can
1787-
/// return a tuple. In that case, the result is Sized only if
1788-
/// all elements of the tuple are Sized.
1789-
///
1790-
/// This is generally the `struct_tail` if this is a struct, or a
1791-
/// tuple of them if this is an enum.
1792-
///
17931769
/// Oddly enough, checking that the sized-constraint is Sized is
17941770
/// actually more expressive than checking all members:
17951771
/// the Sized trait is inductive, so an associated type that references
17961772
/// Self would prevent its containing ADT from being Sized.
17971773
///
17981774
/// Due to normalization being eager, this applies even if
17991775
/// the associated type is behind a pointer, e.g. issue #31299.
1800-
pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Ty<'tcx> {
1776+
pub fn sized_constraint(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> &'tcx [Ty<'tcx>] {
18011777
match queries::adt_sized_constraint::try_get(tcx, DUMMY_SP, self.did) {
1802-
Ok(ty) => ty,
1778+
Ok(tys) => tys,
18031779
Err(_) => {
18041780
debug!("adt_sized_constraint: {:?} is recursive", self);
18051781
// This should be reported as an error by `check_representable`.
18061782
//
18071783
// Consider the type as Sized in the meanwhile to avoid
18081784
// further errors.
1809-
tcx.types.err
1785+
tcx.intern_type_list(&[tcx.types.err])
18101786
}
18111787
}
18121788
}
@@ -1836,18 +1812,13 @@ impl<'a, 'gcx, 'tcx> AdtDef {
18361812

18371813
TyAdt(adt, substs) => {
18381814
// recursive case
1839-
let adt_ty =
1840-
adt.sized_constraint(tcx)
1841-
.subst(tcx, substs);
1815+
let adt_tys = adt.sized_constraint(tcx);
18421816
debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
1843-
ty, adt_ty);
1844-
if let ty::TyTuple(ref tys, _) = adt_ty.sty {
1845-
tys.iter().flat_map(|ty| {
1846-
self.sized_constraint_for_ty(tcx, ty)
1847-
}).collect()
1848-
} else {
1849-
self.sized_constraint_for_ty(tcx, adt_ty)
1850-
}
1817+
ty, adt_tys);
1818+
adt_tys.iter()
1819+
.map(|ty| ty.subst(tcx, substs))
1820+
.flat_map(|ty| self.sized_constraint_for_ty(tcx, ty))
1821+
.collect()
18511822
}
18521823

18531824
TyProjection(..) | TyAnon(..) => {
@@ -2697,13 +2668,7 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
26972668

26982669
/// Calculates the Sized-constraint.
26992670
///
2700-
/// As the Sized-constraint of enums can be a *set* of types,
2701-
/// the Sized-constraint may need to be a set also. Because introducing
2702-
/// a new type of IVar is currently a complex affair, the Sized-constraint
2703-
/// may be a tuple.
2704-
///
2705-
/// In fact, there are only a few options for the constraint:
2706-
/// - `bool`, if the type is always Sized
2671+
/// In fact, there are only a few options for the types in the constraint:
27072672
/// - an obviously-unsized type
27082673
/// - a type parameter or projection whose Sizedness can't be known
27092674
/// - a tuple of type parameters or projections, if there are multiple
@@ -2712,26 +2677,50 @@ fn associated_item<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, def_id: DefId)
27122677
/// check should catch this case.
27132678
fn adt_sized_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
27142679
def_id: DefId)
2715-
-> Ty<'tcx> {
2680+
-> &'tcx [Ty<'tcx>] {
27162681
let def = tcx.lookup_adt_def(def_id);
27172682

2718-
let tys: Vec<_> = def.variants.iter().flat_map(|v| {
2683+
let result = tcx.intern_type_list(&def.variants.iter().flat_map(|v| {
27192684
v.fields.last()
27202685
}).flat_map(|f| {
2721-
let ty = tcx.item_type(f.did);
2722-
def.sized_constraint_for_ty(tcx, ty)
2723-
}).collect();
2724-
2725-
let ty = match tys.len() {
2726-
_ if tys.references_error() => tcx.types.err,
2727-
0 => tcx.types.bool,
2728-
1 => tys[0],
2729-
_ => tcx.intern_tup(&tys[..], false)
2730-
};
2686+
def.sized_constraint_for_ty(tcx, tcx.item_type(f.did))
2687+
}).collect::<Vec<_>>());
27312688

2732-
debug!("adt_sized_constraint: {:?} => {:?}", def, ty);
2689+
debug!("adt_sized_constraint: {:?} => {:?}", def, result);
27332690

2734-
ty
2691+
result
2692+
}
2693+
2694+
/// Calculates the dtorck constraint for a type.
2695+
fn adt_dtorck_constraint<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
2696+
def_id: DefId)
2697+
-> DtorckConstraint<'tcx> {
2698+
let def = tcx.lookup_adt_def(def_id);
2699+
let span = tcx.def_span(def_id);
2700+
debug!("dtorck_constraint: {:?}", def);
2701+
2702+
if def.is_phantom_data() {
2703+
let result = DtorckConstraint {
2704+
outlives: vec![],
2705+
dtorck_types: vec![
2706+
tcx.mk_param_from_def(&tcx.item_generics(def_id).types[0])
2707+
]
2708+
};
2709+
debug!("dtorck_constraint: {:?} => {:?}", def, result);
2710+
return result;
2711+
}
2712+
2713+
let mut result = def.all_fields()
2714+
.map(|field| tcx.item_type(field.did))
2715+
.map(|fty| tcx.dtorck_constraint_for_ty(span, fty, 0, fty))
2716+
.collect::<Result<DtorckConstraint, ErrorReported>>()
2717+
.unwrap_or(DtorckConstraint::empty());
2718+
result.outlives.extend(tcx.destructor_constraints(def));
2719+
result.dedup();
2720+
2721+
debug!("dtorck_constraint: {:?} => {:?}", def, result);
2722+
2723+
result
27352724
}
27362725

27372726
fn associated_item_def_ids<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
@@ -2762,13 +2751,15 @@ pub fn provide(providers: &mut ty::maps::Providers) {
27622751
associated_item,
27632752
associated_item_def_ids,
27642753
adt_sized_constraint,
2754+
adt_dtorck_constraint,
27652755
..*providers
27662756
};
27672757
}
27682758

27692759
pub fn provide_extern(providers: &mut ty::maps::Providers) {
27702760
*providers = ty::maps::Providers {
27712761
adt_sized_constraint,
2762+
adt_dtorck_constraint,
27722763
..*providers
27732764
};
27742765
}
@@ -2784,3 +2775,46 @@ pub fn provide_extern(providers: &mut ty::maps::Providers) {
27842775
pub struct CrateInherentImpls {
27852776
pub inherent_impls: DefIdMap<Rc<Vec<DefId>>>,
27862777
}
2778+
2779+
/// A set of constraints that need to be satisfied in order for
2780+
/// a type to be valid for destruction.
2781+
#[derive(Clone, Debug)]
2782+
pub struct DtorckConstraint<'tcx> {
2783+
/// Types that are required to be alive in order for this
2784+
/// type to be valid for destruction.
2785+
pub outlives: Vec<ty::subst::Kind<'tcx>>,
2786+
/// Types that could not be resolved: projections and params.
2787+
pub dtorck_types: Vec<Ty<'tcx>>,
2788+
}
2789+
2790+
impl<'tcx> FromIterator<DtorckConstraint<'tcx>> for DtorckConstraint<'tcx>
2791+
{
2792+
fn from_iter<I: IntoIterator<Item=DtorckConstraint<'tcx>>>(iter: I) -> Self {
2793+
let mut result = Self::empty();
2794+
2795+
for constraint in iter {
2796+
result.outlives.extend(constraint.outlives);
2797+
result.dtorck_types.extend(constraint.dtorck_types);
2798+
}
2799+
2800+
result
2801+
}
2802+
}
2803+
2804+
2805+
impl<'tcx> DtorckConstraint<'tcx> {
2806+
fn empty() -> DtorckConstraint<'tcx> {
2807+
DtorckConstraint {
2808+
outlives: vec![],
2809+
dtorck_types: vec![]
2810+
}
2811+
}
2812+
2813+
fn dedup<'a>(&mut self) {
2814+
let mut outlives = FxHashSet();
2815+
let mut dtorck_types = FxHashSet();
2816+
2817+
self.outlives.retain(|&val| outlives.replace(val).is_none());
2818+
self.dtorck_types.retain(|&val| dtorck_types.replace(val).is_none());
2819+
}
2820+
}

0 commit comments

Comments
 (0)