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.
This commit is contained in:
Ariel Ben-Yehuda 2017-03-01 18:42:26 +02:00
parent e1cb9ba221
commit e294fd5ecb
11 changed files with 133 additions and 129 deletions

View file

@ -17,6 +17,7 @@ use middle::region;
use rustc::ty::subst::{Subst, Substs};
use rustc::ty::{self, AdtKind, Ty, TyCtxt};
use rustc::traits::{self, ObligationCause, Reveal};
use util::common::ErrorReported;
use util::nodemap::FxHashSet;
use syntax::ast;
@ -40,7 +41,8 @@ use syntax_pos::Span;
/// cannot do `struct S<T>; impl<T:Clone> Drop for S<T> { ... }`).
///
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_predicates = tcx.item_predicates(drop_impl_did);
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_ty: Ty<'tcx>,
self_type_did: DefId)
-> Result<(), ()>
-> Result<(), ErrorReported>
{
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();
@ -106,14 +108,14 @@ fn ensure_drop_params_and_item_params_correspond<'a, 'tcx>(
"Use same sequence of generic type and region \
parameters that is on the struct/enum definition")
.emit();
return Err(());
return Err(ErrorReported);
}
}
if let Err(ref errors) = fulfillment_cx.select_all_or_error(&infcx) {
// this could be reached when we get lazy normalization
infcx.report_fulfillment_errors(errors);
return Err(());
return Err(ErrorReported);
}
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>,
self_type_did: DefId,
self_to_impl_substs: &Substs<'tcx>)
-> Result<(), ()>
-> Result<(), ErrorReported>
{
let mut result = Ok(());
// Here is an example, analogous to that from
// `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 struct/enum definition")
.emit();
result = Err(ErrorReported);
}
}
if tcx.sess.has_errors() {
return Err(());
}
Ok(())
result
}
/// 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.
let dtor_method = adt_def.destructor(tcx)
.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 revised_ty = revise_self_ty(tcx, adt_def, impl_def_id, substs);
return DropckKind::RevisedSelf(revised_ty);

View file

@ -609,31 +609,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) {
*providers = Providers {
typeck_tables,
closure_type,
closure_kind,
adt_destructor,
..*providers
};
}
@ -652,6 +633,12 @@ fn closure_kind<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
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>,
def_id: DefId)
-> &'tcx ty::TypeckTables<'tcx> {
@ -901,9 +888,11 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
id: ast::NodeId,
span: Span) {
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);
if tcx.lookup_adt_def(def_id).repr.simd {
if def.repr.simd {
check_simd(tcx, span, def_id);
}
}
@ -911,7 +900,10 @@ fn check_struct<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
fn check_union<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
id: ast::NodeId,
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) {
@ -926,10 +918,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));
}
hir::ItemEnum(ref enum_definition, _) => {
check_enum_variants(tcx,
it.span,
&enum_definition.variants,
it.id);
check_enum(tcx,
it.span,
&enum_definition.variants,
it.id);
}
hir::ItemFn(..) => {} // entirely within check_item_body
hir::ItemImpl(.., ref impl_item_refs) => {
@ -1322,12 +1314,13 @@ pub fn check_simd<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>, sp: Span, def_id: DefId
}
#[allow(trivial_numeric_casts)]
pub fn check_enum_variants<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
sp: Span,
vs: &'tcx [hir::Variant],
id: ast::NodeId) {
pub fn check_enum<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
sp: Span,
vs: &'tcx [hir::Variant],
id: ast::NodeId) {
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
if vs.is_empty() && tcx.has_attr(def_id, "repr") {
struct_span_err!(

View file

@ -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, "drop-impl checking", || check::check_drop_impls(tcx))?;
check_unused::check_crate(tcx);
check_for_entry_fn(tcx);