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
This commit is contained in:
@@ -79,8 +79,6 @@ pub enum DepNode<D: Clone + Debug> {
|
|||||||
Variance,
|
Variance,
|
||||||
WfCheck(D),
|
WfCheck(D),
|
||||||
TypeckItemType(D),
|
TypeckItemType(D),
|
||||||
Dropck,
|
|
||||||
DropckImpl(D),
|
|
||||||
UnusedTraitCheck,
|
UnusedTraitCheck,
|
||||||
CheckConst(D),
|
CheckConst(D),
|
||||||
Privacy,
|
Privacy,
|
||||||
@@ -114,6 +112,7 @@ pub enum DepNode<D: Clone + Debug> {
|
|||||||
ItemSignature(D),
|
ItemSignature(D),
|
||||||
TypeParamPredicates((D, D)),
|
TypeParamPredicates((D, D)),
|
||||||
SizedConstraint(D),
|
SizedConstraint(D),
|
||||||
|
AdtDestructor(D),
|
||||||
AssociatedItemDefIds(D),
|
AssociatedItemDefIds(D),
|
||||||
InherentImpls(D),
|
InherentImpls(D),
|
||||||
TypeckBodiesKrate,
|
TypeckBodiesKrate,
|
||||||
@@ -229,7 +228,6 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||||||
EntryPoint => Some(EntryPoint),
|
EntryPoint => Some(EntryPoint),
|
||||||
CheckEntryFn => Some(CheckEntryFn),
|
CheckEntryFn => Some(CheckEntryFn),
|
||||||
Variance => Some(Variance),
|
Variance => Some(Variance),
|
||||||
Dropck => Some(Dropck),
|
|
||||||
UnusedTraitCheck => Some(UnusedTraitCheck),
|
UnusedTraitCheck => Some(UnusedTraitCheck),
|
||||||
Privacy => Some(Privacy),
|
Privacy => Some(Privacy),
|
||||||
Reachability => Some(Reachability),
|
Reachability => Some(Reachability),
|
||||||
@@ -256,7 +254,6 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||||||
CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck),
|
CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck),
|
||||||
WfCheck(ref d) => op(d).map(WfCheck),
|
WfCheck(ref d) => op(d).map(WfCheck),
|
||||||
TypeckItemType(ref d) => op(d).map(TypeckItemType),
|
TypeckItemType(ref d) => op(d).map(TypeckItemType),
|
||||||
DropckImpl(ref d) => op(d).map(DropckImpl),
|
|
||||||
CheckConst(ref d) => op(d).map(CheckConst),
|
CheckConst(ref d) => op(d).map(CheckConst),
|
||||||
IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
|
IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
|
||||||
MatchCheck(ref d) => op(d).map(MatchCheck),
|
MatchCheck(ref d) => op(d).map(MatchCheck),
|
||||||
@@ -272,6 +269,7 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||||||
Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
|
Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
|
||||||
}
|
}
|
||||||
SizedConstraint(ref d) => op(d).map(SizedConstraint),
|
SizedConstraint(ref d) => op(d).map(SizedConstraint),
|
||||||
|
AdtDestructor(ref d) => op(d).map(AdtDestructor),
|
||||||
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
|
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
|
||||||
InherentImpls(ref d) => op(d).map(InherentImpls),
|
InherentImpls(ref d) => op(d).map(InherentImpls),
|
||||||
TypeckTables(ref d) => op(d).map(TypeckTables),
|
TypeckTables(ref d) => op(d).map(TypeckTables),
|
||||||
@@ -303,4 +301,3 @@ impl<D: Clone + Debug> DepNode<D> {
|
|||||||
/// them even in the absence of a tcx.)
|
/// them even in the absence of a tcx.)
|
||||||
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
|
||||||
pub struct WorkProductId(pub String);
|
pub struct WorkProductId(pub String);
|
||||||
|
|
||||||
|
|||||||
@@ -333,6 +333,7 @@ define_maps! { <'tcx>
|
|||||||
|
|
||||||
pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
|
pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
|
||||||
pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
|
pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
|
||||||
|
pub adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
|
||||||
pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>,
|
pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>,
|
||||||
|
|
||||||
/// Maps from def-id of a type or region parameter to its
|
/// Maps from def-id of a type or region parameter to its
|
||||||
|
|||||||
@@ -1273,17 +1273,31 @@ impl<'a, 'tcx> ParameterEnvironment<'tcx> {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#[derive(Copy, Clone, Debug)]
|
||||||
|
pub struct Destructor {
|
||||||
|
/// The def-id of the destructor method
|
||||||
|
pub did: DefId,
|
||||||
|
/// Invoking the destructor of a dtorck type during usual cleanup
|
||||||
|
/// (e.g. the glue emitted for stack unwinding) requires all
|
||||||
|
/// lifetimes in the type-structure of `adt` to strictly outlive
|
||||||
|
/// the adt value itself.
|
||||||
|
///
|
||||||
|
/// If `adt` is not dtorck, then the adt's destructor can be
|
||||||
|
/// invoked even when there are lifetimes in the type-structure of
|
||||||
|
/// `adt` that do not strictly outlive the adt value itself.
|
||||||
|
/// (This allows programs to make cyclic structures without
|
||||||
|
/// resorting to unasfe means; see RFCs 769 and 1238).
|
||||||
|
pub is_dtorck: bool,
|
||||||
|
}
|
||||||
|
|
||||||
bitflags! {
|
bitflags! {
|
||||||
flags AdtFlags: u32 {
|
flags AdtFlags: u32 {
|
||||||
const NO_ADT_FLAGS = 0,
|
const NO_ADT_FLAGS = 0,
|
||||||
const IS_ENUM = 1 << 0,
|
const IS_ENUM = 1 << 0,
|
||||||
const IS_DTORCK = 1 << 1, // is this a dtorck type?
|
const IS_PHANTOM_DATA = 1 << 1,
|
||||||
const IS_DTORCK_VALID = 1 << 2,
|
const IS_FUNDAMENTAL = 1 << 2,
|
||||||
const IS_PHANTOM_DATA = 1 << 3,
|
const IS_UNION = 1 << 3,
|
||||||
const IS_FUNDAMENTAL = 1 << 4,
|
const IS_BOX = 1 << 4,
|
||||||
const IS_UNION = 1 << 5,
|
|
||||||
const IS_BOX = 1 << 6,
|
|
||||||
const IS_DTOR_VALID = 1 << 7,
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1325,8 +1339,7 @@ pub struct FieldDef {
|
|||||||
pub struct AdtDef {
|
pub struct AdtDef {
|
||||||
pub did: DefId,
|
pub did: DefId,
|
||||||
pub variants: Vec<VariantDef>,
|
pub variants: Vec<VariantDef>,
|
||||||
destructor: Cell<Option<DefId>>,
|
flags: AdtFlags,
|
||||||
flags: Cell<AdtFlags>,
|
|
||||||
pub repr: ReprOptions,
|
pub repr: ReprOptions,
|
||||||
}
|
}
|
||||||
|
|
||||||
@@ -1425,19 +1438,11 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
|||||||
AdtDef {
|
AdtDef {
|
||||||
did: did,
|
did: did,
|
||||||
variants: variants,
|
variants: variants,
|
||||||
flags: Cell::new(flags),
|
flags: flags,
|
||||||
destructor: Cell::new(None),
|
|
||||||
repr: repr,
|
repr: repr,
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
fn calculate_dtorck(&'gcx self, tcx: TyCtxt) {
|
|
||||||
if tcx.is_adt_dtorck(self) {
|
|
||||||
self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK);
|
|
||||||
}
|
|
||||||
self.flags.set(self.flags.get() | AdtFlags::IS_DTORCK_VALID)
|
|
||||||
}
|
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_struct(&self) -> bool {
|
pub fn is_struct(&self) -> bool {
|
||||||
!self.is_union() && !self.is_enum()
|
!self.is_union() && !self.is_enum()
|
||||||
@@ -1445,12 +1450,12 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
|||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_union(&self) -> bool {
|
pub fn is_union(&self) -> bool {
|
||||||
self.flags.get().intersects(AdtFlags::IS_UNION)
|
self.flags.intersects(AdtFlags::IS_UNION)
|
||||||
}
|
}
|
||||||
|
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_enum(&self) -> bool {
|
pub fn is_enum(&self) -> bool {
|
||||||
self.flags.get().intersects(AdtFlags::IS_ENUM)
|
self.flags.intersects(AdtFlags::IS_ENUM)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns the kind of the ADT - Struct or Enum.
|
/// Returns the kind of the ADT - Struct or Enum.
|
||||||
@@ -1486,29 +1491,26 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
|||||||
/// alive; Otherwise, only the contents are required to be.
|
/// alive; Otherwise, only the contents are required to be.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool {
|
pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool {
|
||||||
if !self.flags.get().intersects(AdtFlags::IS_DTORCK_VALID) {
|
self.destructor(tcx).map_or(false, |d| d.is_dtorck)
|
||||||
self.calculate_dtorck(tcx)
|
|
||||||
}
|
|
||||||
self.flags.get().intersects(AdtFlags::IS_DTORCK)
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this type is #[fundamental] for the purposes
|
/// Returns whether this type is #[fundamental] for the purposes
|
||||||
/// of coherence checking.
|
/// of coherence checking.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_fundamental(&self) -> bool {
|
pub fn is_fundamental(&self) -> bool {
|
||||||
self.flags.get().intersects(AdtFlags::IS_FUNDAMENTAL)
|
self.flags.intersects(AdtFlags::IS_FUNDAMENTAL)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this is PhantomData<T>.
|
/// Returns true if this is PhantomData<T>.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_phantom_data(&self) -> bool {
|
pub fn is_phantom_data(&self) -> bool {
|
||||||
self.flags.get().intersects(AdtFlags::IS_PHANTOM_DATA)
|
self.flags.intersects(AdtFlags::IS_PHANTOM_DATA)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this is Box<T>.
|
/// Returns true if this is Box<T>.
|
||||||
#[inline]
|
#[inline]
|
||||||
pub fn is_box(&self) -> bool {
|
pub fn is_box(&self) -> bool {
|
||||||
self.flags.get().intersects(AdtFlags::IS_BOX)
|
self.flags.intersects(AdtFlags::IS_BOX)
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns whether this type has a destructor.
|
/// Returns whether this type has a destructor.
|
||||||
@@ -1568,38 +1570,6 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
|
|
||||||
if self.flags.get().intersects(AdtFlags::IS_DTOR_VALID) {
|
|
||||||
return self.destructor.get();
|
|
||||||
}
|
|
||||||
|
|
||||||
let dtor = self.destructor_uncached(tcx);
|
|
||||||
self.destructor.set(dtor);
|
|
||||||
self.flags.set(self.flags.get() | AdtFlags::IS_DTOR_VALID);
|
|
||||||
|
|
||||||
dtor
|
|
||||||
}
|
|
||||||
|
|
||||||
fn destructor_uncached(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<DefId> {
|
|
||||||
let drop_trait = if let Some(def_id) = tcx.lang_items.drop_trait() {
|
|
||||||
def_id
|
|
||||||
} else {
|
|
||||||
return None;
|
|
||||||
};
|
|
||||||
|
|
||||||
queries::coherent_trait::get(tcx, DUMMY_SP, (LOCAL_CRATE, drop_trait));
|
|
||||||
|
|
||||||
let mut dtor = None;
|
|
||||||
let ty = tcx.item_type(self.did);
|
|
||||||
tcx.lookup_trait_def(drop_trait).for_each_relevant_impl(tcx, ty, |def_id| {
|
|
||||||
if let Some(item) = tcx.associated_items(def_id).next() {
|
|
||||||
dtor = Some(item.def_id);
|
|
||||||
}
|
|
||||||
});
|
|
||||||
|
|
||||||
dtor
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
|
pub fn discriminants(&'a self, tcx: TyCtxt<'a, 'gcx, 'tcx>)
|
||||||
-> impl Iterator<Item=ConstInt> + 'a {
|
-> impl Iterator<Item=ConstInt> + 'a {
|
||||||
let repr_type = self.repr.discr_type();
|
let repr_type = self.repr.discr_type();
|
||||||
@@ -1621,6 +1591,10 @@ impl<'a, 'gcx, 'tcx> AdtDef {
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub fn destructor(&self, tcx: TyCtxt<'a, 'gcx, 'tcx>) -> Option<Destructor> {
|
||||||
|
queries::adt_destructor::get(tcx, DUMMY_SP, self.did)
|
||||||
|
}
|
||||||
|
|
||||||
/// Returns a simpler type such that `Self: Sized` if and only
|
/// Returns a simpler type such that `Self: Sized` if and only
|
||||||
/// if that type is Sized, or `TyErr` if this type is recursive.
|
/// if that type is Sized, or `TyErr` if this type is recursive.
|
||||||
///
|
///
|
||||||
|
|||||||
@@ -10,7 +10,7 @@
|
|||||||
|
|
||||||
//! misc. type-system utilities too small to deserve their own file
|
//! misc. type-system utilities too small to deserve their own file
|
||||||
|
|
||||||
use hir::def_id::DefId;
|
use hir::def_id::{DefId, LOCAL_CRATE};
|
||||||
use hir::map::DefPathData;
|
use hir::map::DefPathData;
|
||||||
use infer::InferCtxt;
|
use infer::InferCtxt;
|
||||||
use hir::map as hir_map;
|
use hir::map as hir_map;
|
||||||
@@ -20,6 +20,7 @@ use ty::{ParameterEnvironment};
|
|||||||
use ty::fold::TypeVisitor;
|
use ty::fold::TypeVisitor;
|
||||||
use ty::layout::{Layout, LayoutError};
|
use ty::layout::{Layout, LayoutError};
|
||||||
use ty::TypeVariants::*;
|
use ty::TypeVariants::*;
|
||||||
|
use util::common::ErrorReported;
|
||||||
use util::nodemap::FxHashMap;
|
use util::nodemap::FxHashMap;
|
||||||
use middle::lang_items;
|
use middle::lang_items;
|
||||||
|
|
||||||
@@ -32,7 +33,7 @@ use std::hash::Hash;
|
|||||||
use std::intrinsics;
|
use std::intrinsics;
|
||||||
use syntax::ast::{self, Name};
|
use syntax::ast::{self, Name};
|
||||||
use syntax::attr::{self, SignedInt, UnsignedInt};
|
use syntax::attr::{self, SignedInt, UnsignedInt};
|
||||||
use syntax_pos::Span;
|
use syntax_pos::{Span, DUMMY_SP};
|
||||||
|
|
||||||
use hir;
|
use hir;
|
||||||
|
|
||||||
@@ -346,22 +347,33 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||||||
hasher.finish()
|
hasher.finish()
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Returns true if this ADT is a dtorck type.
|
/// Calculate the destructor of a given type.
|
||||||
///
|
pub fn calculate_dtor(
|
||||||
/// Invoking the destructor of a dtorck type during usual cleanup
|
self,
|
||||||
/// (e.g. the glue emitted for stack unwinding) requires all
|
adt_did: DefId,
|
||||||
/// lifetimes in the type-structure of `adt` to strictly outlive
|
validate: &mut FnMut(Self, DefId) -> Result<(), ErrorReported>
|
||||||
/// the adt value itself.
|
) -> Option<ty::Destructor> {
|
||||||
///
|
let drop_trait = if let Some(def_id) = self.lang_items.drop_trait() {
|
||||||
/// If `adt` is not dtorck, then the adt's destructor can be
|
def_id
|
||||||
/// invoked even when there are lifetimes in the type-structure of
|
} else {
|
||||||
/// `adt` that do not strictly outlive the adt value itself.
|
return None;
|
||||||
/// (This allows programs to make cyclic structures without
|
};
|
||||||
/// resorting to unasfe means; see RFCs 769 and 1238).
|
|
||||||
pub fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool {
|
ty::queries::coherent_trait::get(self, DUMMY_SP, (LOCAL_CRATE, drop_trait));
|
||||||
let dtor_method = match adt.destructor(self) {
|
|
||||||
|
let mut dtor_did = None;
|
||||||
|
let ty = self.item_type(adt_did);
|
||||||
|
self.lookup_trait_def(drop_trait).for_each_relevant_impl(self, ty, |impl_did| {
|
||||||
|
if let Some(item) = self.associated_items(impl_did).next() {
|
||||||
|
if let Ok(()) = validate(self, impl_did) {
|
||||||
|
dtor_did = Some(item.def_id);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
});
|
||||||
|
|
||||||
|
let dtor_did = match dtor_did {
|
||||||
Some(dtor) => dtor,
|
Some(dtor) => dtor,
|
||||||
None => return false
|
None => return None
|
||||||
};
|
};
|
||||||
|
|
||||||
// RFC 1238: if the destructor method is tagged with the
|
// RFC 1238: if the destructor method is tagged with the
|
||||||
@@ -373,7 +385,8 @@ impl<'a, 'gcx, 'tcx> TyCtxt<'a, 'gcx, 'tcx> {
|
|||||||
// Such access can be in plain sight (e.g. dereferencing
|
// Such access can be in plain sight (e.g. dereferencing
|
||||||
// `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden
|
// `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden
|
||||||
// (e.g. calling `foo.0.clone()` of `Foo<T:Clone>`).
|
// (e.g. calling `foo.0.clone()` of `Foo<T:Clone>`).
|
||||||
return !self.has_attr(dtor_method, "unsafe_destructor_blind_to_params");
|
let is_dtorck = !self.has_attr(dtor_did, "unsafe_destructor_blind_to_params");
|
||||||
|
Some(ty::Destructor { did: dtor_did, is_dtorck: is_dtorck })
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn closure_base_def_id(&self, def_id: DefId) -> DefId {
|
pub fn closure_base_def_id(&self, def_id: DefId) -> DefId {
|
||||||
|
|||||||
@@ -76,6 +76,10 @@ provide! { <'tcx> tcx, def_id, cdata
|
|||||||
tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx))
|
tcx.alloc_trait_def(cdata.get_trait_def(def_id.index, tcx))
|
||||||
}
|
}
|
||||||
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
|
adt_def => { cdata.get_adt_def(def_id.index, tcx) }
|
||||||
|
adt_destructor => {
|
||||||
|
let _ = cdata;
|
||||||
|
tcx.calculate_dtor(def_id, &mut |_,_| Ok(()))
|
||||||
|
}
|
||||||
variances => { Rc::new(cdata.get_item_variances(def_id.index)) }
|
variances => { Rc::new(cdata.get_item_variances(def_id.index)) }
|
||||||
associated_item_def_ids => {
|
associated_item_def_ids => {
|
||||||
let mut result = vec![];
|
let mut result = vec![];
|
||||||
|
|||||||
@@ -753,12 +753,12 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
|||||||
|
|
||||||
// If the type implements Drop, also add a translation item for the
|
// If the type implements Drop, also add a translation item for the
|
||||||
// monomorphized Drop::drop() implementation.
|
// monomorphized Drop::drop() implementation.
|
||||||
let destructor_did = match ty.sty {
|
let destructor = match ty.sty {
|
||||||
ty::TyAdt(def, _) => def.destructor(scx.tcx()),
|
ty::TyAdt(def, _) => def.destructor(scx.tcx()),
|
||||||
_ => None
|
_ => None
|
||||||
};
|
};
|
||||||
|
|
||||||
if let (Some(destructor_did), false) = (destructor_did, ty.is_box()) {
|
if let (Some(destructor), false) = (destructor, ty.is_box()) {
|
||||||
use rustc::ty::ToPolyTraitRef;
|
use rustc::ty::ToPolyTraitRef;
|
||||||
|
|
||||||
let drop_trait_def_id = scx.tcx()
|
let drop_trait_def_id = scx.tcx()
|
||||||
@@ -778,9 +778,9 @@ fn find_drop_glue_neighbors<'a, 'tcx>(scx: &SharedCrateContext<'a, 'tcx>,
|
|||||||
_ => bug!()
|
_ => bug!()
|
||||||
};
|
};
|
||||||
|
|
||||||
if should_trans_locally(scx.tcx(), destructor_did) {
|
if should_trans_locally(scx.tcx(), destructor.did) {
|
||||||
let trans_item = create_fn_trans_item(scx,
|
let trans_item = create_fn_trans_item(scx,
|
||||||
destructor_did,
|
destructor.did,
|
||||||
substs,
|
substs,
|
||||||
scx.tcx().intern_substs(&[]));
|
scx.tcx().intern_substs(&[]));
|
||||||
output.push(trans_item);
|
output.push(trans_item);
|
||||||
|
|||||||
@@ -265,7 +265,7 @@ pub fn implement_drop_glue<'a, 'tcx>(ccx: &CrateContext<'a, 'tcx>, g: DropGlueKi
|
|||||||
traits::VtableImpl(data) => data,
|
traits::VtableImpl(data) => data,
|
||||||
_ => bug!("dtor for {:?} is not an impl???", t)
|
_ => bug!("dtor for {:?} is not an impl???", t)
|
||||||
};
|
};
|
||||||
let dtor_did = def.destructor(tcx).unwrap();
|
let dtor_did = def.destructor(tcx).unwrap().did;
|
||||||
let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
|
let callee = Callee::def(bcx.ccx, dtor_did, vtbl.substs);
|
||||||
let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
|
let fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
|
||||||
let llret;
|
let llret;
|
||||||
|
|||||||
@@ -17,6 +17,7 @@ use middle::region;
|
|||||||
use rustc::ty::subst::{Subst, Substs};
|
use rustc::ty::subst::{Subst, Substs};
|
||||||
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
|
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
|
||||||
use rustc::traits::{self, ObligationCause, Reveal};
|
use rustc::traits::{self, ObligationCause, Reveal};
|
||||||
|
use util::common::ErrorReported;
|
||||||
use util::nodemap::FxHashSet;
|
use util::nodemap::FxHashSet;
|
||||||
|
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
@@ -40,7 +41,8 @@ use syntax_pos::Span;
|
|||||||
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
|
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
|
||||||
///
|
///
|
||||||
pub fn check_drop_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub fn check_drop_impl<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
drop_impl_did: DefId) -> Result<(), ()> {
|
drop_impl_did: DefId)
|
||||||
|
-> Result<(), ErrorReported> {
|
||||||
let dtor_self_type = tcx.item_type(drop_impl_did);
|
let dtor_self_type = tcx.item_type(drop_impl_did);
|
||||||
let dtor_predicates = tcx.item_predicates(drop_impl_did);
|
let dtor_predicates = tcx.item_predicates(drop_impl_did);
|
||||||
match dtor_self_type.sty {
|
match dtor_self_type.sty {
|
||||||
@@ -72,7 +74,7 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
|
|||||||
drop_impl_did: DefId,
|
drop_impl_did: DefId,
|
||||||
drop_impl_ty: Ty<'tcx>,
|
drop_impl_ty: Ty<'tcx>,
|
||||||
self_type_did: DefId)
|
self_type_did: DefId)
|
||||||
-> Result<(), ()>
|
-> Result<(), ErrorReported>
|
||||||
{
|
{
|
||||||
let drop_impl_node_id = tcx.hir.as_local_node_id(drop_impl_did).unwrap();
|
let drop_impl_node_id = tcx.hir.as_local_node_id(drop_impl_did).unwrap();
|
||||||
let self_type_node_id = tcx.hir.as_local_node_id(self_type_did).unwrap();
|
let self_type_node_id = tcx.hir.as_local_node_id(self_type_did).unwrap();
|
||||||
@@ -106,14 +108,14 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
|
|||||||
"Use same sequence of generic type and region \
|
"Use same sequence of generic type and region \
|
||||||
parameters that is on the struct/enum definition")
|
parameters that is on the struct/enum definition")
|
||||||
.emit();
|
.emit();
|
||||||
return Err(());
|
return Err(ErrorReported);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
|
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
|
||||||
// this could be reached when we get lazy normalization
|
// this could be reached when we get lazy normalization
|
||||||
infcx.report_fulfillment_errors(errors);
|
infcx.report_fulfillment_errors(errors);
|
||||||
return Err(());
|
return Err(ErrorReported);
|
||||||
}
|
}
|
||||||
|
|
||||||
let free_regions = FreeRegionMap::new();
|
let free_regions = FreeRegionMap::new();
|
||||||
@@ -130,8 +132,9 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
|
|||||||
dtor_predicates: &ty::GenericPredicates<'tcx>,
|
dtor_predicates: &ty::GenericPredicates<'tcx>,
|
||||||
self_type_did: DefId,
|
self_type_did: DefId,
|
||||||
self_to_impl_substs: &Substs<'tcx>)
|
self_to_impl_substs: &Substs<'tcx>)
|
||||||
-> Result<(), ()>
|
-> Result<(), ErrorReported>
|
||||||
{
|
{
|
||||||
|
let mut result = Ok(());
|
||||||
|
|
||||||
// Here is an example, analogous to that from
|
// Here is an example, analogous to that from
|
||||||
// `compare_impl_method`.
|
// `compare_impl_method`.
|
||||||
@@ -207,13 +210,11 @@ fn ensure_drop_predicates_are_implied_by_item_defn<'a, 'tcx>(
|
|||||||
"The same requirement must be part of \
|
"The same requirement must be part of \
|
||||||
the struct/enum definition")
|
the struct/enum definition")
|
||||||
.emit();
|
.emit();
|
||||||
|
result = Err(ErrorReported);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
if tcx.sess.has_errors() {
|
result
|
||||||
return Err(());
|
|
||||||
}
|
|
||||||
Ok(())
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// check_safety_of_destructor_if_necessary confirms that the type
|
/// check_safety_of_destructor_if_necessary confirms that the type
|
||||||
@@ -556,7 +557,7 @@ fn has_dtor_of_interest<'a, 'gcx, 'tcx>(tcx: TyCtxt<'a, 'gcx, 'tcx>,
|
|||||||
// attributes attached to the impl's generics.
|
// attributes attached to the impl's generics.
|
||||||
let dtor_method = adt_def.destructor(tcx)
|
let dtor_method = adt_def.destructor(tcx)
|
||||||
.expect("dtorck type without destructor impossible");
|
.expect("dtorck type without destructor impossible");
|
||||||
let method = tcx.associated_item(dtor_method);
|
let method = tcx.associated_item(dtor_method.did);
|
||||||
let impl_def_id = method.container.id();
|
let impl_def_id = method.container.id();
|
||||||
let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs);
|
let revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs);
|
||||||
return DropckKind::RevisedSelf(revised_ty);
|
return DropckKind::RevisedSelf(revised_ty);
|
||||||
|
|||||||
@@ -548,31 +548,12 @@ pub fn check_item_bodies<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult
|
|||||||
})
|
})
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_drop_impls<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) -> CompileResult {
|
|
||||||
tcx.sess.track_errors(|| {
|
|
||||||
let _task = tcx.dep_graph.in_task(DepNode::Dropck);
|
|
||||||
let drop_trait = match tcx.lang_items.drop_trait() {
|
|
||||||
Some(id) => tcx.lookup_trait_def(id), None => { return }
|
|
||||||
};
|
|
||||||
drop_trait.for_each_impl(tcx, |drop_impl_did| {
|
|
||||||
let _task = tcx.dep_graph.in_task(DepNode::DropckImpl(drop_impl_did));
|
|
||||||
if drop_impl_did.is_local() {
|
|
||||||
match dropck::check_drop_impl(tcx, drop_impl_did) {
|
|
||||||
Ok(()) => {}
|
|
||||||
Err(()) => {
|
|
||||||
assert!(tcx.sess.has_errors());
|
|
||||||
}
|
|
||||||
}
|
|
||||||
}
|
|
||||||
});
|
|
||||||
})
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn provide(providers: &mut Providers) {
|
pub fn provide(providers: &mut Providers) {
|
||||||
*providers = Providers {
|
*providers = Providers {
|
||||||
typeck_tables,
|
typeck_tables,
|
||||||
closure_type,
|
closure_type,
|
||||||
closure_kind,
|
closure_kind,
|
||||||
|
adt_destructor,
|
||||||
..*providers
|
..*providers
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
@@ -591,6 +572,12 @@ fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||||||
tcx.item_tables(def_id).closure_kinds[&node_id]
|
tcx.item_tables(def_id).closure_kinds[&node_id]
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn adt_destructor<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
|
def_id: DefId)
|
||||||
|
-> Option<ty::Destructor> {
|
||||||
|
tcx.calculate_dtor(def_id, &mut dropck::check_drop_impl)
|
||||||
|
}
|
||||||
|
|
||||||
fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
fn typeck_tables<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
def_id: DefId)
|
def_id: DefId)
|
||||||
-> &'tcx ty::TypeckTables<'tcx> {
|
-> &'tcx ty::TypeckTables<'tcx> {
|
||||||
@@ -840,9 +827,11 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||||||
id: ast::NodeId,
|
id: ast::NodeId,
|
||||||
span: Span) {
|
span: Span) {
|
||||||
let def_id = tcx.hir.local_def_id(id);
|
let def_id = tcx.hir.local_def_id(id);
|
||||||
|
let def = tcx.lookup_adt_def(def_id);
|
||||||
|
def.destructor(tcx); // force the destructor to be evaluated
|
||||||
check_representable(tcx, span, def_id);
|
check_representable(tcx, span, def_id);
|
||||||
|
|
||||||
if tcx.lookup_adt_def(def_id).repr.simd {
|
if def.repr.simd {
|
||||||
check_simd(tcx, span, def_id);
|
check_simd(tcx, span, def_id);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -850,7 +839,10 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
|||||||
fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
id: ast::NodeId,
|
id: ast::NodeId,
|
||||||
span: Span) {
|
span: Span) {
|
||||||
check_representable(tcx, span, tcx.hir.local_def_id(id));
|
let def_id = tcx.hir.local_def_id(id);
|
||||||
|
let def = tcx.lookup_adt_def(def_id);
|
||||||
|
def.destructor(tcx); // force the destructor to be evaluated
|
||||||
|
check_representable(tcx, span, def_id);
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
|
pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item) {
|
||||||
@@ -865,10 +857,10 @@ pub fn check_item_type<'a,'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, it: &'tcx hir::Item
|
|||||||
tcx.item_tables(tcx.hir.local_def_id(it.id));
|
tcx.item_tables(tcx.hir.local_def_id(it.id));
|
||||||
}
|
}
|
||||||
hir::ItemEnum(ref enum_definition, _) => {
|
hir::ItemEnum(ref enum_definition, _) => {
|
||||||
check_enum_variants(tcx,
|
check_enum(tcx,
|
||||||
it.span,
|
it.span,
|
||||||
&enum_definition.variants,
|
&enum_definition.variants,
|
||||||
it.id);
|
it.id);
|
||||||
}
|
}
|
||||||
hir::ItemFn(..) => {} // entirely within check_item_body
|
hir::ItemFn(..) => {} // entirely within check_item_body
|
||||||
hir::ItemImpl(.., ref impl_item_refs) => {
|
hir::ItemImpl(.., ref impl_item_refs) => {
|
||||||
@@ -1261,12 +1253,13 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId
|
|||||||
}
|
}
|
||||||
|
|
||||||
#[allow(trivial_numeric_casts)]
|
#[allow(trivial_numeric_casts)]
|
||||||
pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
|
||||||
sp: Span,
|
sp: Span,
|
||||||
vs: &'tcx [hir::Variant],
|
vs: &'tcx [hir::Variant],
|
||||||
id: ast::NodeId) {
|
id: ast::NodeId) {
|
||||||
let def_id = tcx.hir.local_def_id(id);
|
let def_id = tcx.hir.local_def_id(id);
|
||||||
let def = tcx.lookup_adt_def(def_id);
|
let def = tcx.lookup_adt_def(def_id);
|
||||||
|
def.destructor(tcx); // force the destructor to be evaluated
|
||||||
|
|
||||||
if vs.is_empty() && tcx.has_attr(def_id, "repr") {
|
if vs.is_empty() && tcx.has_attr(def_id, "repr") {
|
||||||
struct_span_err!(
|
struct_span_err!(
|
||||||
|
|||||||
@@ -322,8 +322,6 @@ pub fn check_crate<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>)
|
|||||||
|
|
||||||
time(time_passes, "item-bodies checking", || check::check_item_bodies(tcx))?;
|
time(time_passes, "item-bodies checking", || check::check_item_bodies(tcx))?;
|
||||||
|
|
||||||
time(time_passes, "drop-impl checking", || check::check_drop_impls(tcx))?;
|
|
||||||
|
|
||||||
check_unused::check_crate(tcx);
|
check_unused::check_crate(tcx);
|
||||||
check_for_entry_fn(tcx);
|
check_for_entry_fn(tcx);
|
||||||
|
|
||||||
|
|||||||
23
src/test/compile-fail/issue-38868.rs
Normal file
23
src/test/compile-fail/issue-38868.rs
Normal file
@@ -0,0 +1,23 @@
|
|||||||
|
// Copyright 2017 The Rust Project Developers. See the COPYRIGHT
|
||||||
|
// file at the top-level directory of this distribution and at
|
||||||
|
// http://rust-lang.org/COPYRIGHT.
|
||||||
|
//
|
||||||
|
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
|
||||||
|
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
|
||||||
|
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
|
||||||
|
// option. This file may not be copied, modified, or distributed
|
||||||
|
// except according to those terms.
|
||||||
|
|
||||||
|
pub struct List<T> {
|
||||||
|
head: T,
|
||||||
|
}
|
||||||
|
|
||||||
|
impl Drop for List<i32> { //~ ERROR E0366
|
||||||
|
fn drop(&mut self) {
|
||||||
|
panic!()
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
fn main() {
|
||||||
|
List { head: 0 };
|
||||||
|
}
|
||||||
Reference in New Issue
Block a user