From 7119974f82cb239307ed9ea2e885eb66c0edba95 Mon Sep 17 00:00:00 2001 From: Niko Matsakis Date: Sat, 20 Sep 2014 09:19:45 -0400 Subject: [PATCH] Move unsafe destructor check from kind.rs into wf.rs --- src/librustc/diagnostics.rs | 1 - src/librustc/middle/kind.rs | 81 ------------------- src/librustc/middle/traits/mod.rs | 3 + src/librustc/middle/typeck/check/vtable2.rs | 8 ++ src/librustc/middle/typeck/check/wf.rs | 46 +++++++++++ .../compile-fail/kindck-destructor-owned.rs | 22 ++++- 6 files changed, 78 insertions(+), 83 deletions(-) diff --git a/src/librustc/diagnostics.rs b/src/librustc/diagnostics.rs index 20842beae16..a3ca3802e47 100644 --- a/src/librustc/diagnostics.rs +++ b/src/librustc/diagnostics.rs @@ -130,7 +130,6 @@ register_diagnostics!( E0121, E0122, E0124, - E0125, E0126, E0127, E0128, diff --git a/src/librustc/middle/kind.rs b/src/librustc/middle/kind.rs index f5d4ece3bcc..b065e09692c 100644 --- a/src/librustc/middle/kind.rs +++ b/src/librustc/middle/kind.rs @@ -9,15 +9,11 @@ // except according to those terms. use middle::mem_categorization::Typer; -use middle::subst; use middle::ty; -use middle::ty_fold::TypeFoldable; -use middle::ty_fold; use util::ppaux::{ty_to_string}; use util::ppaux::UserString; use syntax::ast::*; -use syntax::attr; use syntax::codemap::Span; use syntax::print::pprust::{expr_to_string, ident_to_string}; use syntax::visit::Visitor; @@ -48,10 +44,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> { check_ty(self, t); } - fn visit_item(&mut self, i: &Item) { - check_item(self, i); - } - fn visit_pat(&mut self, p: &Pat) { check_pat(self, p); } @@ -65,79 +57,6 @@ pub fn check_crate(tcx: &ty::ctxt) { tcx.sess.abort_if_errors(); } -struct EmptySubstsFolder<'a, 'tcx: 'a> { - tcx: &'a ty::ctxt<'tcx> -} -impl<'a, 'tcx> ty_fold::TypeFolder<'tcx> for EmptySubstsFolder<'a, 'tcx> { - fn tcx<'a>(&'a self) -> &'a ty::ctxt<'tcx> { - self.tcx - } - fn fold_substs(&mut self, _: &subst::Substs) -> subst::Substs { - subst::Substs::empty() - } -} - -fn check_struct_safe_for_destructor(cx: &mut Context, - span: Span, - struct_did: DefId) { - let struct_tpt = ty::lookup_item_type(cx.tcx, struct_did); - if !struct_tpt.generics.has_type_params(subst::TypeSpace) - && !struct_tpt.generics.has_region_params(subst::TypeSpace) { - let mut folder = EmptySubstsFolder { tcx: cx.tcx }; - if !ty::type_is_sendable(cx.tcx, struct_tpt.ty.fold_with(&mut folder)) { - span_err!(cx.tcx.sess, span, E0125, - "cannot implement a destructor on a \ - structure or enumeration that does not satisfy Send"); - span_note!(cx.tcx.sess, span, - "use \"#[unsafe_destructor]\" on the implementation \ - to force the compiler to allow this"); - } - } else { - span_err!(cx.tcx.sess, span, E0141, - "cannot implement a destructor on a structure \ - with type parameters"); - span_note!(cx.tcx.sess, span, - "use \"#[unsafe_destructor]\" on the implementation \ - to force the compiler to allow this"); - } -} - -fn check_impl_of_trait(cx: &mut Context, it: &Item, trait_ref: &TraitRef, self_type: &Ty) { - let ast_trait_def = *cx.tcx.def_map.borrow() - .find(&trait_ref.ref_id) - .expect("trait ref not in def map!"); - let trait_def_id = ast_trait_def.def_id(); - - // If this is a destructor, check kinds. - if cx.tcx.lang_items.drop_trait() == Some(trait_def_id) && - !attr::contains_name(it.attrs.as_slice(), "unsafe_destructor") - { - match self_type.node { - TyPath(_, ref bounds, path_node_id) => { - assert!(bounds.is_none()); - let struct_def = cx.tcx.def_map.borrow().get_copy(&path_node_id); - let struct_did = struct_def.def_id(); - check_struct_safe_for_destructor(cx, self_type.span, struct_did); - } - _ => { - cx.tcx.sess.span_bug(self_type.span, - "the self type for the Drop trait impl is not a path"); - } - } - } -} - -fn check_item(cx: &mut Context, item: &Item) { - match item.node { - ItemImpl(_, Some(ref trait_ref), ref self_type, _) => { - check_impl_of_trait(cx, item, trait_ref, &**self_type); - } - _ => {} - } - - visit::walk_item(cx, item) -} - // Yields the appropriate function to check the kind of closed over // variables. `id` is the NodeId for some expression that creates the // closure. diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs index ad3e1ae0242..4ce32383525 100644 --- a/src/librustc/middle/traits/mod.rs +++ b/src/librustc/middle/traits/mod.rs @@ -69,6 +69,9 @@ pub enum ObligationCauseCode { /// Obligation incurred due to an object cast. ObjectCastObligation(/* Object type */ ty::t), + /// To implement drop, type must be sendable. + DropTrait, + /// Various cases where expressions must be sized/copy/etc: AssignmentLhsSized, // L = X implies that L is Sized StructInitializerSized, // S { ... } must be Sized diff --git a/src/librustc/middle/typeck/check/vtable2.rs b/src/librustc/middle/typeck/check/vtable2.rs index 63a17cec575..e0bf04a1cc3 100644 --- a/src/librustc/middle/typeck/check/vtable2.rs +++ b/src/librustc/middle/typeck/check/vtable2.rs @@ -390,5 +390,13 @@ fn note_obligation_cause(fcx: &FnCtxt, obligation.cause.span, "structs must have a statically known size to be initialized"); } + traits::DropTrait => { + span_note!(tcx.sess, obligation.cause.span, + "cannot implement a destructor on a \ + structure or enumeration that does not satisfy Send"); + span_note!(tcx.sess, obligation.cause.span, + "use \"#[unsafe_destructor]\" on the implementation \ + to force the compiler to allow this"); + } } } diff --git a/src/librustc/middle/typeck/check/wf.rs b/src/librustc/middle/typeck/check/wf.rs index 6a63464c4b6..8a7de70ea2b 100644 --- a/src/librustc/middle/typeck/check/wf.rs +++ b/src/librustc/middle/typeck/check/wf.rs @@ -8,6 +8,7 @@ // option. This file may not be copied, modified, or distributed // except according to those terms. +use middle::subst; use middle::subst::{Subst}; use middle::traits; use middle::ty; @@ -21,6 +22,7 @@ use util::ppaux::Repr; use std::collections::HashSet; use syntax::ast; use syntax::ast_util::{local_def}; +use syntax::attr; use syntax::codemap::Span; use syntax::visit; use syntax::visit::Visitor; @@ -165,6 +167,22 @@ impl<'ccx, 'tcx> CheckTypeWellFormedVisitor<'ccx, 'tcx> { }; let trait_ref = (*trait_ref).subst(fcx.tcx(), &fcx.inh.param_env.free_substs); + // There are special rules that apply to drop. + if + fcx.tcx().lang_items.drop_trait() == Some(trait_ref.def_id) && + !attr::contains_name(item.attrs.as_slice(), "unsafe_destructor") + { + match ty::get(self_ty).sty { + ty::ty_struct(def_id, _) | + ty::ty_enum(def_id, _) => { + check_struct_safe_for_destructor(fcx, item.span, self_ty, def_id); + } + _ => { + // Coherence already reports an error in this case. + } + } + } + // We are stricter on the trait-ref in an impl than the // self-type. In particular, we enforce region // relationships. The reason for this is that (at least @@ -362,3 +380,31 @@ impl<'cx,'tcx> TypeFolder<'tcx> for BoundsChecker<'cx,'tcx> { t // we're not folding to produce a new type, so just return `t` here } } + +/////////////////////////////////////////////////////////////////////////// +// Special drop trait checking + +fn check_struct_safe_for_destructor(fcx: &FnCtxt, + span: Span, + self_ty: ty::t, + struct_did: ast::DefId) { + let struct_tpt = ty::lookup_item_type(fcx.tcx(), struct_did); + if !struct_tpt.generics.has_type_params(subst::TypeSpace) + && !struct_tpt.generics.has_region_params(subst::TypeSpace) + { + let cause = traits::ObligationCause::new(span, traits::DropTrait); + fcx.register_obligation( + traits::obligation_for_builtin_bound( + fcx.tcx(), + cause, + self_ty, + ty::BoundSend)); + } else { + span_err!(fcx.tcx().sess, span, E0141, + "cannot implement a destructor on a structure \ + with type parameters"); + span_note!(fcx.tcx().sess, span, + "use \"#[unsafe_destructor]\" on the implementation \ + to force the compiler to allow this"); + } +} diff --git a/src/test/compile-fail/kindck-destructor-owned.rs b/src/test/compile-fail/kindck-destructor-owned.rs index 4197464c600..e50bb8fbede 100644 --- a/src/test/compile-fail/kindck-destructor-owned.rs +++ b/src/test/compile-fail/kindck-destructor-owned.rs @@ -16,7 +16,27 @@ struct Foo { } impl Drop for Foo { -//~^ ERROR cannot implement a destructor on a structure or enumeration that does not satisfy Send +//~^ ERROR the trait `core::kinds::Send` is not implemented for the type `Foo` +//~^^ NOTE cannot implement a destructor on a structure or enumeration that does not satisfy Send + fn drop(&mut self) { + } +} + +struct Bar<'a> { + f: &'a int, +} + +impl<'a> Drop for Bar<'a> { +//~^ ERROR E0141 + fn drop(&mut self) { + } +} + +struct Baz { + f: &'static int, +} + +impl Drop for Baz { fn drop(&mut self) { } }