Skip to content

Commit 042728e

Browse files
committed
Auto merge of #40178 - arielb1:provide-destructors, r=eddyb
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 #38868. Fixes #40132. r? @eddyb
2 parents 2c6e0e4 + e294fd5 commit 042728e

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,
@@ -114,6 +112,7 @@ pub enum DepNode<D: Clone + Debug> {
114112
ItemSignature(D),
115113
TypeParamPredicates((D, D)),
116114
SizedConstraint(D),
115+
AdtDestructor(D),
117116
AssociatedItemDefIds(D),
118117
InherentImpls(D),
119118
TypeckBodiesKrate,
@@ -229,7 +228,6 @@ impl<D: Clone + Debug> DepNode<D> {
229228
EntryPoint => Some(EntryPoint),
230229
CheckEntryFn => Some(CheckEntryFn),
231230
Variance => Some(Variance),
232-
Dropck => Some(Dropck),
233231
UnusedTraitCheck => Some(UnusedTraitCheck),
234232
Privacy => Some(Privacy),
235233
Reachability => Some(Reachability),
@@ -256,7 +254,6 @@ impl<D: Clone + Debug> DepNode<D> {
256254
CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck),
257255
WfCheck(ref d) => op(d).map(WfCheck),
258256
TypeckItemType(ref d) => op(d).map(TypeckItemType),
259-
DropckImpl(ref d) => op(d).map(DropckImpl),
260257
CheckConst(ref d) => op(d).map(CheckConst),
261258
IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
262259
MatchCheck(ref d) => op(d).map(MatchCheck),
@@ -272,6 +269,7 @@ impl<D: Clone + Debug> DepNode<D> {
272269
Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
273270
}
274271
SizedConstraint(ref d) => op(d).map(SizedConstraint),
272+
AdtDestructor(ref d) => op(d).map(AdtDestructor),
275273
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
276274
InherentImpls(ref d) => op(d).map(InherentImpls),
277275
TypeckTables(ref d) => op(d).map(TypeckTables),
@@ -303,4 +301,3 @@ impl<D: Clone + Debug> DepNode<D> {
303301
/// them even in the absence of a tcx.)
304302
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
305303
pub struct WorkProductId(pub String);
306-

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
@@ -1273,17 +1273,31 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
12731273
}
12741274
}
12751275

1276+
#[derive(Copy, Clone, Debug)]
1277+
pub struct Destructor {
1278+
/// The def-id of the destructor method
1279+
pub did: DefId,
1280+
/// Invoking the destructor of a dtorck type during usual cleanup
1281+
/// (e.g. the glue emitted for stack unwinding) requires all
1282+
/// lifetimes in the type-structure of `adt` to strictly outlive
1283+
/// the adt value itself.
1284+
///
1285+
/// If `adt` is not dtorck, then the adt's destructor can be
1286+
/// invoked even when there are lifetimes in the type-structure of
1287+
/// `adt` that do not strictly outlive the adt value itself.
1288+
/// (This allows programs to make cyclic structures without
1289+
/// resorting to unasfe means; see RFCs 769 and 1238).
1290+
pub is_dtorck: bool,
1291+
}
1292+
12761293
bitflags! {
12771294
flags AdtFlags: u32 {
12781295
const NO_ADT_FLAGS = 0,
12791296
const IS_ENUM = 1 << 0,
1280-
const IS_DTORCK = 1 << 1, // is this a dtorck type?
1281-
const IS_DTORCK_VALID = 1 << 2,
1282-
const IS_PHANTOM_DATA = 1 << 3,
1283-
const IS_FUNDAMENTAL = 1 << 4,
1284-
const IS_UNION = 1 << 5,
1285-
const IS_BOX = 1 << 6,
1286-
const IS_DTOR_VALID = 1 << 7,
1297+
const IS_PHANTOM_DATA = 1 << 1,
1298+
const IS_FUNDAMENTAL = 1 << 2,
1299+
const IS_UNION = 1 << 3,
1300+
const IS_BOX = 1 << 4,
12871301
}
12881302
}
12891303

@@ -1325,8 +1339,7 @@ pub struct FieldDef {
13251339
pub struct AdtDef {
13261340
pub did: DefId,
13271341
pub variants: Vec<VariantDef>,
1328-
destructor: Cell<Option<DefId>>,
1329-
flags: Cell<AdtFlags>,
1342+
flags: AdtFlags,
13301343
pub repr: ReprOptions,
13311344
}
13321345

@@ -1425,32 +1438,24 @@ impl<'a, 'gcx, 'tcx> AdtDef {
14251438
AdtDef {
14261439
did: did,
14271440
variants: variants,
1428-
flags: Cell::new(flags),
1429-
destructor: Cell::new(None),
1441+
flags: flags,
14301442
repr: repr,
14311443
}
14321444
}
14331445

1434-
fn calculate_dtorck(&'gcx self, tcx: TyCtxt) {
1435-
if tcx.is_adt_dtorck(self) {
1436-
self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK);
1437-
}
1438-
self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID)
1439-
}
1440-
14411446
#[inline]
14421447
pub fn is_struct(&self) -> bool {
14431448
!self.is_union() && !self.is_enum()
14441449
}
14451450

14461451
#[inline]
14471452
pub fn is_union(&self) -> bool {
1448-
self.flags.get().intersects(AdtFlags::IS_UNION)
1453+
self.flags.intersects(AdtFlags::IS_UNION)
14491454
}
14501455

14511456
#[inline]
14521457
pub fn is_enum(&self) -> bool {
1453-
self.flags.get().intersects(AdtFlags::IS_ENUM)
1458+
self.flags.intersects(AdtFlags::IS_ENUM)
14541459
}
14551460

14561461
/// Returns the kind of the ADT - Struct or Enum.
@@ -1486,29 +1491,26 @@ impl<'a, 'gcx, 'tcx> AdtDef {
14861491
/// alive; Otherwise, only the contents are required to be.
14871492
#[inline]
14881493
pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool {
1489-
if !self.flags.get().intersects(AdtFlags::IS_DTORCK_VALID) {
1490-
self.calculate_dtorck(tcx)
1491-
}
1492-
self.flags.get().intersects(AdtFlags::IS_DTORCK)
1494+
self.destructor(tcx).map_or(false, |d| d.is_dtorck)
14931495
}
14941496

14951497
/// Returns whether this type is #[fundamental] for the purposes
14961498
/// of coherence checking.
14971499
#[inline]
14981500
pub fn is_fundamental(&self) -> bool {
1499-
self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL)
1501+
self.flags.intersects(AdtFlags::IS_FUNDAMENTAL)
15001502
}
15011503

15021504
/// Returns true if this is PhantomData<T>.
15031505
#[inline]
15041506
pub fn is_phantom_data(&self) -> bool {
1505-
self.flags.get().intersects(AdtFlags::IS_PHANTOM_DATA)
1507+
self.flags.intersects(AdtFlags::IS_PHANTOM_DATA)
15061508
}
15071509

15081510
/// Returns true if this is Box<T>.
15091511
#[inline]
15101512
pub fn is_box(&self) -> bool {
1511-
self.flags.get().intersects(AdtFlags::IS_BOX)
1513+
self.flags.intersects(AdtFlags::IS_BOX)
15121514
}
15131515

15141516
/// Returns whether this type has a destructor.
@@ -1568,38 +1570,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
15681570
}
15691571
}
15701572

1571-
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
1572-
if self.flags.get().intersects(AdtFlags::IS_DTOR_VALID) {
1573-
return self.destructor.get();
1574-
}
1575-
1576-
let dtor = self.destructor_uncached(tcx);
1577-
self.destructor.set(dtor);
1578-
self.flags.set(self.flags.get() | AdtFlags::IS_DTOR_VALID);
1579-
1580-
dtor
1581-
}
1582-
1583-
fn destructor_uncached(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
1584-
let drop_trait = if let Some(def_id) = tcx.lang_items.drop_trait() {
1585-
def_id
1586-
} else {
1587-
return None;
1588-
};
1589-
1590-
queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, drop_trait));
1591-
1592-
let mut dtor = None;
1593-
let ty = tcx.item_type(self.did);
1594-
tcx.lookup_trait_def(drop_trait).for_each_relevant_impl(tcx, ty, |def_id| {
1595-
if let Some(item) = tcx.associated_items(def_id).next() {
1596-
dtor = Some(item.def_id);
1597-
}
1598-
});
1599-
1600-
dtor
1601-
}
1602-
16031573
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
16041574
-> impl Iterator<Item=ConstInt> + 'a {
16051575
let repr_type = self.repr.discr_type();
@@ -1621,6 +1591,10 @@ impl<'a, 'gcx, 'tcx> AdtDef {
16211591
})
16221592
}
16231593

1594+
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
1595+
queries::adt_destructor::get(tcx, DUMMY_SP, self.did)
1596+
}
1597+
16241598
/// Returns a simpler type such that `Self: Sized` if and only
16251599
/// if that type is Sized, or `TyErr` if this type is recursive.
16261600
///

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)