Skip to content

Commit af83d98

Browse files
committed
Auto merge of #28001 - arielb1:dtor-fixes, r=pnkfelix
r? @pnkfelix
2 parents fd302a9 + 277eeb9 commit af83d98

File tree

20 files changed

+256
-250
lines changed

20 files changed

+256
-250
lines changed

src/librustc/middle/check_const.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -548,7 +548,7 @@ fn check_expr<'a, 'tcx>(v: &mut CheckCrateVisitor<'a, 'tcx>,
548548
e: &ast::Expr, node_ty: Ty<'tcx>) {
549549
match node_ty.sty {
550550
ty::TyStruct(def, _) |
551-
ty::TyEnum(def, _) if def.has_dtor(v.tcx) => {
551+
ty::TyEnum(def, _) if def.has_dtor() => {
552552
v.add_qualif(ConstQualif::NEEDS_DROP);
553553
if v.mode != Mode::Var {
554554
v.tcx.sess.span_err(e.span,

src/librustc/middle/expr_use_visitor.rs

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,9 @@ impl OverloadedCallType {
239239
// mem_categorization, it requires a TYPER, which is a type that
240240
// supplies types from the tree. After type checking is complete, you
241241
// can just use the tcx as the typer.
242-
243-
pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d> {
242+
//
243+
// FIXME(stage0): the :'t here is probably only important for stage0
244+
pub struct ExprUseVisitor<'d, 't, 'a: 't, 'tcx:'a+'d+'t> {
244245
typer: &'t infer::InferCtxt<'a, 'tcx>,
245246
mc: mc::MemCategorizationContext<'t, 'a, 'tcx>,
246247
delegate: &'d mut (Delegate<'tcx>+'d),

src/librustc/middle/infer/higher_ranked/mod.rs

Lines changed: 0 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,6 @@
1414
use super::{CombinedSnapshot, InferCtxt, HigherRankedType, SkolemizationMap};
1515
use super::combine::CombineFields;
1616

17-
use middle::subst;
1817
use middle::ty::{self, TypeError, Binder};
1918
use middle::ty_fold::{self, TypeFoldable};
2019
use middle::ty_relate::{Relate, RelateResult, TypeRelation};
@@ -455,63 +454,6 @@ impl<'a,'tcx> InferCtxtExt for InferCtxt<'a,'tcx> {
455454
}
456455
}
457456

458-
/// Constructs and returns a substitution that, for a given type
459-
/// scheme parameterized by `generics`, will replace every generic
460-
/// parameter in the type with a skolemized type/region (which one can
461-
/// think of as a "fresh constant", except at the type/region level of
462-
/// reasoning).
463-
///
464-
/// Since we currently represent bound/free type parameters in the
465-
/// same way, this only has an effect on regions.
466-
///
467-
/// (Note that unlike a substitution from `ty::construct_free_substs`,
468-
/// this inserts skolemized regions rather than free regions; this
469-
/// allows one to use `fn leak_check` to catch attmepts to unify the
470-
/// skolemized regions with e.g. the `'static` lifetime)
471-
pub fn construct_skolemized_substs<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
472-
generics: &ty::Generics<'tcx>,
473-
snapshot: &CombinedSnapshot)
474-
-> (subst::Substs<'tcx>, SkolemizationMap)
475-
{
476-
let mut map = FnvHashMap();
477-
478-
// map T => T
479-
let mut types = subst::VecPerParamSpace::empty();
480-
push_types_from_defs(infcx.tcx, &mut types, generics.types.as_slice());
481-
482-
// map early- or late-bound 'a => fresh 'a
483-
let mut regions = subst::VecPerParamSpace::empty();
484-
push_region_params(infcx, &mut map, &mut regions, generics.regions.as_slice(), snapshot);
485-
486-
let substs = subst::Substs { types: types,
487-
regions: subst::NonerasedRegions(regions) };
488-
return (substs, map);
489-
490-
fn push_region_params<'a,'tcx>(infcx: &InferCtxt<'a,'tcx>,
491-
map: &mut SkolemizationMap,
492-
regions: &mut subst::VecPerParamSpace<ty::Region>,
493-
region_params: &[ty::RegionParameterDef],
494-
snapshot: &CombinedSnapshot)
495-
{
496-
for r in region_params {
497-
let br = r.to_bound_region();
498-
let skol_var = infcx.region_vars.new_skolemized(br, &snapshot.region_vars_snapshot);
499-
let sanity_check = map.insert(br, skol_var);
500-
assert!(sanity_check.is_none());
501-
regions.push(r.space, skol_var);
502-
}
503-
}
504-
505-
fn push_types_from_defs<'tcx>(tcx: &ty::ctxt<'tcx>,
506-
types: &mut subst::VecPerParamSpace<ty::Ty<'tcx>>,
507-
defs: &[ty::TypeParameterDef<'tcx>]) {
508-
for def in defs {
509-
let ty = tcx.mk_param_from_def(def);
510-
types.push(def.space, ty);
511-
}
512-
}
513-
}
514-
515457
pub fn skolemize_late_bound_regions<'a,'tcx,T>(infcx: &InferCtxt<'a,'tcx>,
516458
binder: &ty::Binder<T>,
517459
snapshot: &CombinedSnapshot)

src/librustc/middle/infer/mod.rs

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -948,15 +948,6 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
948948
})
949949
}
950950

951-
pub fn construct_skolemized_subst(&self,
952-
generics: &ty::Generics<'tcx>,
953-
snapshot: &CombinedSnapshot)
954-
-> (subst::Substs<'tcx>, SkolemizationMap) {
955-
/*! See `higher_ranked::construct_skolemized_subst` */
956-
957-
higher_ranked::construct_skolemized_substs(self, generics, snapshot)
958-
}
959-
960951
pub fn skolemize_late_bound_regions<T>(&self,
961952
value: &ty::Binder<T>,
962953
snapshot: &CombinedSnapshot)

src/librustc/middle/infer/region_inference/mod.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -373,7 +373,7 @@ impl<'a, 'tcx> RegionVarBindings<'a, 'tcx> {
373373

374374
let sc = self.skolemization_count.get();
375375
self.skolemization_count.set(sc + 1);
376-
ReSkolemized(sc, br)
376+
ReSkolemized(ty::SkolemizedRegionVid { index: sc }, br)
377377
}
378378

379379
pub fn new_bound(&self, debruijn: ty::DebruijnIndex) -> Region {

src/librustc/middle/reachable.rs

Lines changed: 5 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -355,9 +355,11 @@ impl<'a, 'tcx> ReachableContext<'a, 'tcx> {
355355
// this properly would result in the necessity of computing *type*
356356
// reachability, which might result in a compile time loss.
357357
fn mark_destructors_reachable(&mut self) {
358-
for (_, destructor_def_id) in self.tcx.destructor_for_type.borrow().iter() {
359-
if destructor_def_id.is_local() {
360-
self.reachable_symbols.insert(destructor_def_id.node);
358+
for adt in self.tcx.adt_defs() {
359+
if let Some(destructor_def_id) = adt.destructor() {
360+
if destructor_def_id.is_local() {
361+
self.reachable_symbols.insert(destructor_def_id.node);
362+
}
361363
}
362364
}
363365
}

src/librustc/middle/ty.rs

Lines changed: 102 additions & 29 deletions
Original file line numberDiff line numberDiff line change
@@ -112,7 +112,7 @@ pub struct CrateAnalysis {
112112
#[derive(Copy, Clone)]
113113
pub enum DtorKind {
114114
NoDtor,
115-
TraitDtor(DefId, bool)
115+
TraitDtor(bool)
116116
}
117117

118118
impl DtorKind {
@@ -126,7 +126,7 @@ impl DtorKind {
126126
pub fn has_drop_flag(&self) -> bool {
127127
match self {
128128
&NoDtor => false,
129-
&TraitDtor(_, flag) => flag
129+
&TraitDtor(flag) => flag
130130
}
131131
}
132132
}
@@ -797,12 +797,6 @@ pub struct ctxt<'tcx> {
797797
/// True if the variance has been computed yet; false otherwise.
798798
pub variance_computed: Cell<bool>,
799799

800-
/// A mapping from the def ID of an enum or struct type to the def ID
801-
/// of the method that implements its destructor. If the type is not
802-
/// present in this map, it does not have a destructor. This map is
803-
/// populated during the coherence phase of typechecking.
804-
pub destructor_for_type: RefCell<DefIdMap<DefId>>,
805-
806800
/// A method will be in this list if and only if it is a destructor.
807801
pub destructors: RefCell<DefIdSet>,
808802

@@ -1502,7 +1496,62 @@ pub struct DebruijnIndex {
15021496
pub depth: u32,
15031497
}
15041498

1505-
/// Representation of regions:
1499+
/// Representation of regions.
1500+
///
1501+
/// Unlike types, most region variants are "fictitious", not concrete,
1502+
/// regions. Among these, `ReStatic`, `ReEmpty` and `ReScope` are the only
1503+
/// ones representing concrete regions.
1504+
///
1505+
/// ## Bound Regions
1506+
///
1507+
/// These are regions that are stored behind a binder and must be substituted
1508+
/// with some concrete region before being used. There are 2 kind of
1509+
/// bound regions: early-bound, which are bound in a TypeScheme/TraitDef,
1510+
/// and are substituted by a Substs, and late-bound, which are part of
1511+
/// higher-ranked types (e.g. `for<'a> fn(&'a ())`) and are substituted by
1512+
/// the likes of `liberate_late_bound_regions`. The distinction exists
1513+
/// because higher-ranked lifetimes aren't supported in all places. See [1][2].
1514+
///
1515+
/// Unlike TyParam-s, bound regions are not supposed to exist "in the wild"
1516+
/// outside their binder, e.g. in types passed to type inference, and
1517+
/// should first be substituted (by skolemized regions, free regions,
1518+
/// or region variables).
1519+
///
1520+
/// ## Skolemized and Free Regions
1521+
///
1522+
/// One often wants to work with bound regions without knowing their precise
1523+
/// identity. For example, when checking a function, the lifetime of a borrow
1524+
/// can end up being assigned to some region parameter. In these cases,
1525+
/// it must be ensured that bounds on the region can't be accidentally
1526+
/// assumed without being checked.
1527+
///
1528+
/// The process of doing that is called "skolemization". The bound regions
1529+
/// are replaced by skolemized markers, which don't satisfy any relation
1530+
/// not explicity provided.
1531+
///
1532+
/// There are 2 kinds of skolemized regions in rustc: `ReFree` and
1533+
/// `ReSkolemized`. When checking an item's body, `ReFree` is supposed
1534+
/// to be used. These also support explicit bounds: both the internally-stored
1535+
/// *scope*, which the region is assumed to outlive, as well as other
1536+
/// relations stored in the `FreeRegionMap`. Note that these relations
1537+
/// aren't checked when you `make_subregion` (or `mk_eqty`), only by
1538+
/// `resolve_regions_and_report_errors`.
1539+
///
1540+
/// When working with higher-ranked types, some region relations aren't
1541+
/// yet known, so you can't just call `resolve_regions_and_report_errors`.
1542+
/// `ReSkolemized` is designed for this purpose. In these contexts,
1543+
/// there's also the risk that some inference variable laying around will
1544+
/// get unified with your skolemized region: if you want to check whether
1545+
/// `for<'a> Foo<'_>: 'a`, and you substitute your bound region `'a`
1546+
/// with a skolemized region `'%a`, the variable `'_` would just be
1547+
/// instantiated to the skolemized region `'%a`, which is wrong because
1548+
/// the inference variable is supposed to satisfy the relation
1549+
/// *for every value of the skolemized region*. To ensure that doesn't
1550+
/// happen, you can use `leak_check`. This is more clearly explained
1551+
/// by infer/higher_ranked/README.md.
1552+
///
1553+
/// [1] http://smallcultfollowing.com/babysteps/blog/2013/10/29/intermingled-parameter-lists/
1554+
/// [2] http://smallcultfollowing.com/babysteps/blog/2013/11/04/intermingled-parameter-lists/
15061555
#[derive(Clone, PartialEq, Eq, Hash, Copy)]
15071556
pub enum Region {
15081557
// Region bound in a type or fn declaration which will be
@@ -1532,7 +1581,7 @@ pub enum Region {
15321581

15331582
/// A skolemized region - basically the higher-ranked version of ReFree.
15341583
/// Should not exist after typeck.
1535-
ReSkolemized(u32, BoundRegion),
1584+
ReSkolemized(SkolemizedRegionVid, BoundRegion),
15361585

15371586
/// Empty lifetime is for data that is never accessed.
15381587
/// Bottom in the region lattice. We treat ReEmpty somewhat
@@ -2168,6 +2217,11 @@ pub struct RegionVid {
21682217
pub index: u32
21692218
}
21702219

2220+
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
2221+
pub struct SkolemizedRegionVid {
2222+
pub index: u32
2223+
}
2224+
21712225
#[derive(Clone, Copy, PartialEq, Eq, Hash)]
21722226
pub enum InferTy {
21732227
TyVar(TyVid),
@@ -2997,7 +3051,7 @@ impl<'a, 'tcx> ParameterEnvironment<'a, 'tcx> {
29973051
_ => return Err(TypeIsStructural),
29983052
};
29993053

3000-
if adt.has_dtor(tcx) {
3054+
if adt.has_dtor() {
30013055
return Err(TypeHasDestructor)
30023056
}
30033057

@@ -3202,6 +3256,7 @@ bitflags! {
32023256
const IS_PHANTOM_DATA = 1 << 3,
32033257
const IS_SIMD = 1 << 4,
32043258
const IS_FUNDAMENTAL = 1 << 5,
3259+
const IS_NO_DROP_FLAG = 1 << 6,
32053260
}
32063261
}
32073262

@@ -3252,6 +3307,7 @@ pub struct FieldDefData<'tcx, 'container: 'tcx> {
32523307
pub struct AdtDefData<'tcx, 'container: 'tcx> {
32533308
pub did: DefId,
32543309
pub variants: Vec<VariantDefData<'tcx, 'container>>,
3310+
destructor: Cell<Option<DefId>>,
32553311
flags: Cell<AdtFlags>,
32563312
}
32573313

@@ -3287,6 +3343,9 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
32873343
if attr::contains_name(&attrs, "fundamental") {
32883344
flags = flags | AdtFlags::IS_FUNDAMENTAL;
32893345
}
3346+
if attr::contains_name(&attrs, "unsafe_no_drop_flag") {
3347+
flags = flags | AdtFlags::IS_NO_DROP_FLAG;
3348+
}
32903349
if tcx.lookup_simd(did) {
32913350
flags = flags | AdtFlags::IS_SIMD;
32923351
}
@@ -3300,6 +3359,7 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
33003359
did: did,
33013360
variants: variants,
33023361
flags: Cell::new(flags),
3362+
destructor: Cell::new(None)
33033363
}
33043364
}
33053365

@@ -3350,8 +3410,11 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
33503410
}
33513411

33523412
/// Returns whether this type has a destructor.
3353-
pub fn has_dtor(&self, tcx: &ctxt<'tcx>) -> bool {
3354-
tcx.destructor_for_type.borrow().contains_key(&self.did)
3413+
pub fn has_dtor(&self) -> bool {
3414+
match self.dtor_kind() {
3415+
NoDtor => false,
3416+
TraitDtor(..) => true
3417+
}
33553418
}
33563419

33573420
/// Asserts this is a struct and returns the struct's unique
@@ -3413,6 +3476,24 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
34133476
_ => panic!("unexpected def {:?} in variant_of_def", def)
34143477
}
34153478
}
3479+
3480+
pub fn destructor(&self) -> Option<DefId> {
3481+
self.destructor.get()
3482+
}
3483+
3484+
pub fn set_destructor(&self, dtor: DefId) {
3485+
assert!(self.destructor.get().is_none());
3486+
self.destructor.set(Some(dtor));
3487+
}
3488+
3489+
pub fn dtor_kind(&self) -> DtorKind {
3490+
match self.destructor.get() {
3491+
Some(_) => {
3492+
TraitDtor(!self.flags.get().intersects(AdtFlags::IS_NO_DROP_FLAG))
3493+
}
3494+
None => NoDtor,
3495+
}
3496+
}
34163497
}
34173498

34183499
impl<'tcx, 'container> VariantDefData<'tcx, 'container> {
@@ -3796,7 +3877,6 @@ impl<'tcx> ctxt<'tcx> {
37963877
normalized_cache: RefCell::new(FnvHashMap()),
37973878
lang_items: lang_items,
37983879
provided_method_sources: RefCell::new(DefIdMap()),
3799-
destructor_for_type: RefCell::new(DefIdMap()),
38003880
destructors: RefCell::new(DefIdSet()),
38013881
inherent_impls: RefCell::new(DefIdMap()),
38023882
impl_items: RefCell::new(DefIdMap()),
@@ -4619,7 +4699,7 @@ impl<'tcx> TyS<'tcx> {
46194699
})
46204700
});
46214701

4622-
if def.has_dtor(cx) {
4702+
if def.has_dtor() {
46234703
res = res | TC::OwnsDtor;
46244704
}
46254705

@@ -5957,18 +6037,6 @@ impl<'tcx> ctxt<'tcx> {
59576037
self.with_path(id, |path| ast_map::path_to_string(path))
59586038
}
59596039

5960-
/* If struct_id names a struct with a dtor. */
5961-
pub fn ty_dtor(&self, struct_id: DefId) -> DtorKind {
5962-
match self.destructor_for_type.borrow().get(&struct_id) {
5963-
Some(&method_def_id) => {
5964-
let flag = !self.has_attr(struct_id, "unsafe_no_drop_flag");
5965-
5966-
TraitDtor(method_def_id, flag)
5967-
}
5968-
None => NoDtor,
5969-
}
5970-
}
5971-
59726040
pub fn with_path<T, F>(&self, id: DefId, f: F) -> T where
59736041
F: FnOnce(ast_map::PathElems) -> T,
59746042
{
@@ -6053,6 +6121,11 @@ impl<'tcx> ctxt<'tcx> {
60536121
self.lookup_adt_def_master(did)
60546122
}
60556123

6124+
/// Return the list of all interned ADT definitions
6125+
pub fn adt_defs(&self) -> Vec<AdtDef<'tcx>> {
6126+
self.adt_defs.borrow().values().cloned().collect()
6127+
}
6128+
60566129
/// Given the did of an item, returns its full set of predicates.
60576130
pub fn lookup_predicates(&self, did: DefId) -> GenericPredicates<'tcx> {
60586131
lookup_locally_or_in_crate_store(
@@ -6700,8 +6773,8 @@ impl<'tcx> ctxt<'tcx> {
67006773
/// Returns true if this ADT is a dtorck type, i.e. whether it being
67016774
/// safe for destruction requires it to be alive
67026775
fn is_adt_dtorck(&self, adt: AdtDef<'tcx>) -> bool {
6703-
let dtor_method = match self.destructor_for_type.borrow().get(&adt.did) {
6704-
Some(dtor) => *dtor,
6776+
let dtor_method = match adt.destructor() {
6777+
Some(dtor) => dtor,
67056778
None => return false
67066779
};
67076780
let impl_did = self.impl_of_method(dtor_method).unwrap_or_else(|| {

src/librustc/util/ppaux.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ impl fmt::Debug for ty::Region {
418418
}
419419

420420
ty::ReSkolemized(id, ref bound_region) => {
421-
write!(f, "ReSkolemized({}, {:?})", id, bound_region)
421+
write!(f, "ReSkolemized({}, {:?})", id.index, bound_region)
422422
}
423423

424424
ty::ReEmpty => write!(f, "ReEmpty")

0 commit comments

Comments
 (0)