Skip to content

Commit e294fd5

Browse files
committed
convert AdtDef::destructor to on-demand
This removes the Cell from AdtDef. Also, moving destructor validity checking to on-demand (forced during item-type checking) ensures that invalid destructors can't cause ICEs. Fixes rust-lang#38868. Fixes rust-lang#40132.
1 parent e1cb9ba commit e294fd5

File tree

11 files changed

+133
-129
lines changed

11 files changed

+133
-129
lines changed

src/librustc/dep_graph/dep_node.rs

+2-5
Original file line numberDiff line numberDiff line change
@@ -79,8 +79,6 @@ pub enum DepNode<D: Clone + Debug> {
7979
Variance,
8080
WfCheck(D),
8181
TypeckItemType(D),
82-
Dropck,
83-
DropckImpl(D),
8482
UnusedTraitCheck,
8583
CheckConst(D),
8684
Privacy,
@@ -112,6 +110,7 @@ pub enum DepNode<D: Clone + Debug> {
112110
ItemSignature(D),
113111
TypeParamPredicates((D, D)),
114112
SizedConstraint(D),
113+
AdtDestructor(D),
115114
AssociatedItemDefIds(D),
116115
InherentImpls(D),
117116
TypeckTables(D),
@@ -223,7 +222,6 @@ impl<D: Clone + Debug> DepNode<D> {
223222
EntryPoint => Some(EntryPoint),
224223
CheckEntryFn => Some(CheckEntryFn),
225224
Variance => Some(Variance),
226-
Dropck => Some(Dropck),
227225
UnusedTraitCheck => Some(UnusedTraitCheck),
228226
Privacy => Some(Privacy),
229227
Reachability => Some(Reachability),
@@ -250,7 +248,6 @@ impl<D: Clone + Debug> DepNode<D> {
250248
CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck),
251249
WfCheck(ref d) => op(d).map(WfCheck),
252250
TypeckItemType(ref d) => op(d).map(TypeckItemType),
253-
DropckImpl(ref d) => op(d).map(DropckImpl),
254251
CheckConst(ref d) => op(d).map(CheckConst),
255252
IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
256253
MatchCheck(ref d) => op(d).map(MatchCheck),
@@ -266,6 +263,7 @@ impl<D: Clone + Debug> DepNode<D> {
266263
Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
267264
}
268265
SizedConstraint(ref d) => op(d).map(SizedConstraint),
266+
AdtDestructor(ref d) => op(d).map(AdtDestructor),
269267
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
270268
InherentImpls(ref d) => op(d).map(InherentImpls),
271269
TypeckTables(ref d) => op(d).map(TypeckTables),
@@ -297,4 +295,3 @@ impl<D: Clone + Debug> DepNode<D> {
297295
/// them even in the absence of a tcx.)
298296
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
299297
pub struct WorkProductId(pub String);
300-

src/librustc/ty/maps.rs

+1
Original file line numberDiff line numberDiff line change
@@ -333,6 +333,7 @@ define_maps! { <'tcx>
333333

334334
pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
335335
pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
336+
pub adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
336337
pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>,
337338

338339
/// Maps from def-id of a type or region parameter to its

src/librustc/ty/mod.rs

+33-59
Original file line numberDiff line numberDiff line change
@@ -1291,17 +1291,31 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
12911291
}
12921292
}
12931293

1294+
#[derive(Copy, Clone, Debug)]
1295+
pub struct Destructor {
1296+
/// The def-id of the destructor method
1297+
pub did: DefId,
1298+
/// Invoking the destructor of a dtorck type during usual cleanup
1299+
/// (e.g. the glue emitted for stack unwinding) requires all
1300+
/// lifetimes in the type-structure of `adt` to strictly outlive
1301+
/// the adt value itself.
1302+
///
1303+
/// If `adt` is not dtorck, then the adt's destructor can be
1304+
/// invoked even when there are lifetimes in the type-structure of
1305+
/// `adt` that do not strictly outlive the adt value itself.
1306+
/// (This allows programs to make cyclic structures without
1307+
/// resorting to unasfe means; see RFCs 769 and 1238).
1308+
pub is_dtorck: bool,
1309+
}
1310+
12941311
bitflags! {
12951312
flags AdtFlags: u32 {
12961313
const NO_ADT_FLAGS = 0,
12971314
const IS_ENUM = 1 << 0,
1298-
const IS_DTORCK = 1 << 1, // is this a dtorck type?
1299-
const IS_DTORCK_VALID = 1 << 2,
1300-
const IS_PHANTOM_DATA = 1 << 3,
1301-
const IS_FUNDAMENTAL = 1 << 4,
1302-
const IS_UNION = 1 << 5,
1303-
const IS_BOX = 1 << 6,
1304-
const IS_DTOR_VALID = 1 << 7,
1315+
const IS_PHANTOM_DATA = 1 << 1,
1316+
const IS_FUNDAMENTAL = 1 << 2,
1317+
const IS_UNION = 1 << 3,
1318+
const IS_BOX = 1 << 4,
13051319
}
13061320
}
13071321

@@ -1343,8 +1357,7 @@ pub struct FieldDef {
13431357
pub struct AdtDef {
13441358
pub did: DefId,
13451359
pub variants: Vec<VariantDef>,
1346-
destructor: Cell<Option<DefId>>,
1347-
flags: Cell<AdtFlags>,
1360+
flags: AdtFlags,
13481361
pub repr: ReprOptions,
13491362
}
13501363

@@ -1436,32 +1449,24 @@ impl<'a, 'gcx, 'tcx> AdtDef {
14361449
AdtDef {
14371450
did: did,
14381451
variants: variants,
1439-
flags: Cell::new(flags),
1440-
destructor: Cell::new(None),
1452+
flags: flags,
14411453
repr: repr,
14421454
}
14431455
}
14441456

1445-
fn calculate_dtorck(&'gcx self, tcx: TyCtxt) {
1446-
if tcx.is_adt_dtorck(self) {
1447-
self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK);
1448-
}
1449-
self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID)
1450-
}
1451-
14521457
#[inline]
14531458
pub fn is_struct(&self) -> bool {
14541459
!self.is_union() && !self.is_enum()
14551460
}
14561461

14571462
#[inline]
14581463
pub fn is_union(&self) -> bool {
1459-
self.flags.get().intersects(AdtFlags::IS_UNION)
1464+
self.flags.intersects(AdtFlags::IS_UNION)
14601465
}
14611466

14621467
#[inline]
14631468
pub fn is_enum(&self) -> bool {
1464-
self.flags.get().intersects(AdtFlags::IS_ENUM)
1469+
self.flags.intersects(AdtFlags::IS_ENUM)
14651470
}
14661471

14671472
/// Returns the kind of the ADT - Struct or Enum.
@@ -1497,29 +1502,26 @@ impl<'a, 'gcx, 'tcx> AdtDef {
14971502
/// alive; Otherwise, only the contents are required to be.
14981503
#[inline]
14991504
pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool {
1500-
if !self.flags.get().intersects(AdtFlags::IS_DTORCK_VALID) {
1501-
self.calculate_dtorck(tcx)
1502-
}
1503-
self.flags.get().intersects(AdtFlags::IS_DTORCK)
1505+
self.destructor(tcx).map_or(false, |d| d.is_dtorck)
15041506
}
15051507

15061508
/// Returns whether this type is #[fundamental] for the purposes
15071509
/// of coherence checking.
15081510
#[inline]
15091511
pub fn is_fundamental(&self) -> bool {
1510-
self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL)
1512+
self.flags.intersects(AdtFlags::IS_FUNDAMENTAL)
15111513
}
15121514

15131515
/// Returns true if this is PhantomData<T>.
15141516
#[inline]
15151517
pub fn is_phantom_data(&self) -> bool {
1516-
self.flags.get().intersects(AdtFlags::IS_PHANTOM_DATA)
1518+
self.flags.intersects(AdtFlags::IS_PHANTOM_DATA)
15171519
}
15181520

15191521
/// Returns true if this is Box<T>.
15201522
#[inline]
15211523
pub fn is_box(&self) -> bool {
1522-
self.flags.get().intersects(AdtFlags::IS_BOX)
1524+
self.flags.intersects(AdtFlags::IS_BOX)
15231525
}
15241526

15251527
/// Returns whether this type has a destructor.
@@ -1579,38 +1581,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
15791581
}
15801582
}
15811583

1582-
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
1583-
if self.flags.get().intersects(AdtFlags::IS_DTOR_VALID) {
1584-
return self.destructor.get();
1585-
}
1586-
1587-
let dtor = self.destructor_uncached(tcx);
1588-
self.destructor.set(dtor);
1589-
self.flags.set(self.flags.get() | AdtFlags::IS_DTOR_VALID);
1590-
1591-
dtor
1592-
}
1593-
1594-
fn destructor_uncached(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
1595-
let drop_trait = if let Some(def_id) = tcx.lang_items.drop_trait() {
1596-
def_id
1597-
} else {
1598-
return None;
1599-
};
1600-
1601-
queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, drop_trait));
1602-
1603-
let mut dtor = None;
1604-
let ty = tcx.item_type(self.did);
1605-
tcx.lookup_trait_def(drop_trait).for_each_relevant_impl(tcx, ty, |def_id| {
1606-
if let Some(item) = tcx.associated_items(def_id).next() {
1607-
dtor = Some(item.def_id);
1608-
}
1609-
});
1610-
1611-
dtor
1612-
}
1613-
16141584
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
16151585
-> impl Iterator<Item=ConstInt> + 'a {
16161586
let repr_type = self.repr.discr_type();
@@ -1632,6 +1602,10 @@ impl<'a, 'gcx, 'tcx> AdtDef {
16321602
})
16331603
}
16341604

1605+
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
1606+
queries::adt_destructor::get(tcx, DUMMY_SP, self.did)
1607+
}
1608+
16351609
/// Returns a simpler type such that `Self: Sized` if and only
16361610
/// if that type is Sized, or `TyErr` if this type is recursive.
16371611
///

src/librustc/ty/util.rs

+31-18
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010

1111
//! misc. type-system utilities too small to deserve their own file
1212
13-
use hir::def_id::DefId;
13+
use hir::def_id::{DefId, LOCAL_CRATE};
1414
use hir::map::DefPathData;
1515
use infer::InferCtxt;
1616
use hir::map as hir_map;
@@ -20,6 +20,7 @@ use ty::{ParameterEnvironment};
2020
use ty::fold::TypeVisitor;
2121
use ty::layout::{Layout, LayoutError};
2222
use ty::TypeVariants::*;
23+
use util::common::ErrorReported;
2324
use util::nodemap::FxHashMap;
2425
use middle::lang_items;
2526

@@ -32,7 +33,7 @@ use std::hash::Hash;
3233
use std::intrinsics;
3334
use syntax::ast::{self, Name};
3435
use syntax::attr::{self, SignedInt, UnsignedInt};
35-
use syntax_pos::Span;
36+
use syntax_pos::{Span, DUMMY_SP};
3637

3738
use hir;
3839

@@ -346,22 +347,33 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
346347
hasher.finish()
347348
}
348349

349-
/// Returns true if this ADT is a dtorck type.
350-
///
351-
/// Invoking the destructor of a dtorck type during usual cleanup
352-
/// (e.g. the glue emitted for stack unwinding) requires all
353-
/// lifetimes in the type-structure of `adt` to strictly outlive
354-
/// the adt value itself.
355-
///
356-
/// If `adt` is not dtorck, then the adt's destructor can be
357-
/// invoked even when there are lifetimes in the type-structure of
358-
/// `adt` that do not strictly outlive the adt value itself.
359-
/// (This allows programs to make cyclic structures without
360-
/// resorting to unasfe means; see RFCs 769 and 1238).
361-
pub fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool {
362-
let dtor_method = match adt.destructor(self) {
350+
/// Calculate the destructor of a given type.
351+
pub fn calculate_dtor(
352+
self,
353+
adt_did: DefId,
354+
validate: &mut FnMut(Self, DefId) -> Result<(), ErrorReported>
355+
) -> Option<ty::Destructor> {
356+
let drop_trait = if let Some(def_id) = self.lang_items.drop_trait() {
357+
def_id
358+
} else {
359+
return None;
360+
};
361+
362+
ty::queries::coherent_trait::get(self, DUMMY_SP, (LOCAL_CRATE, drop_trait));
363+
364+
let mut dtor_did = None;
365+
let ty = self.item_type(adt_did);
366+
self.lookup_trait_def(drop_trait).for_each_relevant_impl(self, ty, |impl_did| {
367+
if let Some(item) = self.associated_items(impl_did).next() {
368+
if let Ok(()) = validate(self, impl_did) {
369+
dtor_did = Some(item.def_id);
370+
}
371+
}
372+
});
373+
374+
let dtor_did = match dtor_did {
363375
Some(dtor) => dtor,
364-
None => return false
376+
None => return None
365377
};
366378

367379
// RFC 1238: if the destructor method is tagged with the
@@ -373,7 +385,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
373385
// Such access can be in plain sight (e.g. dereferencing
374386
// `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden
375387
// (e.g. calling `foo.0.clone()` of `Foo<T:Clone>`).
376-
return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params");
388+
let is_dtorck = !self.has_attr(dtor_did, "unsafe_destructor_blind_to_params");
389+
Some(ty::Destructor { did: dtor_did, is_dtorck: is_dtorck })
377390
}
378391

379392
pub fn closure_base_def_id(&self, def_id: DefId) -> DefId {

src/librustc_metadata/cstore_impl.rs

+4
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,10 @@ provide! { <'tcx> tcx, def_id, cdata
7676
tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx))
7777
}
7878
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
79+
adt_destructor => {
80+
let _ = cdata;
81+
tcx.calculate_dtor(def_id, &mut |_,_| Ok(()))
82+
}
7983
variances => { Rc::new(cdata.get_item_variances(def_id.index)) }
8084
associated_item_def_ids => {
8185
let mut result = vec![];

src/librustc_trans/collector.rs

+4-4
Original file line numberDiff line numberDiff line change
@@ -753,12 +753,12 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
753753

754754
// If the type implements Drop, also add a translation item for the
755755
// monomorphized Drop::drop() implementation.
756-
let destructor_did = match ty.sty {
756+
let destructor = match ty.sty {
757757
ty::TyAdt(def, _) => def.destructor(scx.tcx()),
758758
_ => None
759759
};
760760

761-
if let (Some(destructor_did), false) = (destructor_did, ty.is_box()) {
761+
if let (Some(destructor), false) = (destructor, ty.is_box()) {
762762
use rustc::ty::ToPolyTraitRef;
763763

764764
let drop_trait_def_id = scx.tcx()
@@ -778,9 +778,9 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
778778
_ => bug!()
779779
};
780780

781-
if should_trans_locally(scx.tcx(), destructor_did) {
781+
if should_trans_locally(scx.tcx(), destructor.did) {
782782
let trans_item = create_fn_trans_item(scx,
783-
destructor_did,
783+
destructor.did,
784784
substs,
785785
scx.tcx().intern_substs(&[]));
786786
output.push(trans_item);

src/librustc_trans/glue.rs

+1-1
Original file line numberDiff line numberDiff line change
@@ -265,7 +265,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
265265
traits::VtableImpl(data) => data,
266266
_ => bug!("dtor for {:?} is not an impl???", t)
267267
};
268-
let dtor_did = def.destructor(tcx).unwrap();
268+
let dtor_did = def.destructor(tcx).unwrap().did;
269269
let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
270270
let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
271271
let llret;

0 commit comments

Comments
 (0)