Variance,
WfCheck(D),
TypeckItemType(D),
- Dropck,
- DropckImpl(D),
UnusedTraitCheck,
CheckConst(D),
Privacy,
ItemSignature(D),
TypeParamPredicates((D, D)),
SizedConstraint(D),
+ AdtDestructor(D),
AssociatedItemDefIds(D),
InherentImpls(D),
TypeckBodiesKrate,
EntryPoint => Some(EntryPoint),
CheckEntryFn => Some(CheckEntryFn),
Variance => Some(Variance),
- Dropck => Some(Dropck),
UnusedTraitCheck => Some(UnusedTraitCheck),
Privacy => Some(Privacy),
Reachability => Some(Reachability),
CoherenceOrphanCheck(ref d) => op(d).map(CoherenceOrphanCheck),
WfCheck(ref d) => op(d).map(WfCheck),
TypeckItemType(ref d) => op(d).map(TypeckItemType),
- DropckImpl(ref d) => op(d).map(DropckImpl),
CheckConst(ref d) => op(d).map(CheckConst),
IntrinsicCheck(ref d) => op(d).map(IntrinsicCheck),
MatchCheck(ref d) => op(d).map(MatchCheck),
Some(TypeParamPredicates((try_opt!(op(item)), try_opt!(op(param)))))
}
SizedConstraint(ref d) => op(d).map(SizedConstraint),
+ AdtDestructor(ref d) => op(d).map(AdtDestructor),
AssociatedItemDefIds(ref d) => op(d).map(AssociatedItemDefIds),
InherentImpls(ref d) => op(d).map(InherentImpls),
TypeckTables(ref d) => op(d).map(TypeckTables),
/// them even in the absence of a tcx.)
#[derive(Clone, Debug, PartialEq, Eq, PartialOrd, Ord, Hash, RustcEncodable, RustcDecodable)]
pub struct WorkProductId(pub String);
-
pub trait_def: ItemSignature(DefId) -> &'tcx ty::TraitDef,
pub adt_def: ItemSignature(DefId) -> &'tcx ty::AdtDef,
+ pub adt_destructor: AdtDestructor(DefId) -> Option<ty::Destructor>,
pub adt_sized_constraint: SizedConstraint(DefId) -> Ty<'tcx>,
/// Maps from def-id of a type or region parameter to its
}
}
+#[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! {
flags AdtFlags: u32 {
const NO_ADT_FLAGS = 0,
const IS_ENUM = 1 << 0,
- const IS_DTORCK = 1 << 1, // is this a dtorck type?
- const IS_DTORCK_VALID = 1 << 2,
- const IS_PHANTOM_DATA = 1 << 3,
- const IS_FUNDAMENTAL = 1 << 4,
- const IS_UNION = 1 << 5,
- const IS_BOX = 1 << 6,
- const IS_DTOR_VALID = 1 << 7,
+ const IS_PHANTOM_DATA = 1 << 1,
+ const IS_FUNDAMENTAL = 1 << 2,
+ const IS_UNION = 1 << 3,
+ const IS_BOX = 1 << 4,
}
}
pub struct AdtDef {
pub did: DefId,
pub variants: Vec<VariantDef>,
- destructor: Cell<Option<DefId>>,
- flags: Cell<AdtFlags>,
+ flags: AdtFlags,
pub repr: ReprOptions,
}
AdtDef {
did: did,
variants: variants,
- flags: Cell::new(flags),
- destructor: Cell::new(None),
+ flags: flags,
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]
pub fn is_struct(&self) -> bool {
!self.is_union() && !self.is_enum()
#[inline]
pub fn is_union(&self) -> bool {
- self.flags.get().intersects(AdtFlags::IS_UNION)
+ self.flags.intersects(AdtFlags::IS_UNION)
}
#[inline]
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.
/// alive; Otherwise, only the contents are required to be.
#[inline]
pub fn is_dtorck(&'gcx self, tcx: TyCtxt) -> bool {
- if !self.flags.get().intersects(AdtFlags::IS_DTORCK_VALID) {
- self.calculate_dtorck(tcx)
- }
- self.flags.get().intersects(AdtFlags::IS_DTORCK)
+ self.destructor(tcx).map_or(false, |d| d.is_dtorck)
}
/// Returns whether this type is #[fundamental] for the purposes
/// of coherence checking.
#[inline]
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>.
#[inline]
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>.
#[inline]
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.
}
}
- 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>)
-> impl Iterator<Item=ConstInt> + 'a {
let repr_type = self.repr.discr_type();
})
}
+ 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
/// if that type is Sized, or `TyErr` if this type is recursive.
///
//! 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 infer::InferCtxt;
use hir::map as hir_map;
use ty::fold::TypeVisitor;
use ty::layout::{Layout, LayoutError};
use ty::TypeVariants::*;
+use util::common::ErrorReported;
use util::nodemap::FxHashMap;
use middle::lang_items;
use std::intrinsics;
use syntax::ast::{self, Name};
use syntax::attr::{self, SignedInt, UnsignedInt};
-use syntax_pos::Span;
+use syntax_pos::{Span, DUMMY_SP};
use hir;
hasher.finish()
}
- /// Returns true if this ADT is a dtorck type.
- ///
- /// 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 fn is_adt_dtorck(self, adt: &ty::AdtDef) -> bool {
- let dtor_method = match adt.destructor(self) {
+ /// Calculate the destructor of a given type.
+ pub fn calculate_dtor(
+ self,
+ adt_did: DefId,
+ validate: &mut FnMut(Self, DefId) -> Result<(), ErrorReported>
+ ) -> Option<ty::Destructor> {
+ let drop_trait = if let Some(def_id) = self.lang_items.drop_trait() {
+ def_id
+ } else {
+ return None;
+ };
+
+ ty::queries::coherent_trait::get(self, DUMMY_SP, (LOCAL_CRATE, drop_trait));
+
+ 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,
- None => return false
+ None => return None
};
// RFC 1238: if the destructor method is tagged with the
// Such access can be in plain sight (e.g. dereferencing
// `*foo.0` of `Foo<'a>(&'a u32)`) or indirectly hidden
// (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 {
tcx.alloc_trait_def(cdata.get_trait_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)) }
associated_item_def_ids => {
let mut result = vec![];
// If the type implements Drop, also add a translation item for the
// monomorphized Drop::drop() implementation.
- let destructor_did = match ty.sty {
+ let destructor = match ty.sty {
ty::TyAdt(def, _) => def.destructor(scx.tcx()),
_ => 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;
let drop_trait_def_id = scx.tcx()
_ => 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,
- destructor_did,
+ destructor.did,
substs,
scx.tcx().intern_substs(&[]));
output.push(trans_item);
traits::VtableImpl(data) => data,
_ => 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 fn_ty = callee.direct_fn_type(bcx.ccx, &[]);
let llret;
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;
/// 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 {
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();
"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();
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`.
"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
// 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);
})
}
-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
};
}
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> {
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);
}
}
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) {
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) => {
}
#[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!(
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);
--- /dev/null
+// 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 };
+}