Move unsafe destructor check from kind.rs into wf.rs
This commit is contained in:
parent
c31623b0e4
commit
7119974f82
6 changed files with 78 additions and 83 deletions
|
@ -130,7 +130,6 @@ register_diagnostics!(
|
||||||
E0121,
|
E0121,
|
||||||
E0122,
|
E0122,
|
||||||
E0124,
|
E0124,
|
||||||
E0125,
|
|
||||||
E0126,
|
E0126,
|
||||||
E0127,
|
E0127,
|
||||||
E0128,
|
E0128,
|
||||||
|
|
|
@ -9,15 +9,11 @@
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
use middle::mem_categorization::Typer;
|
use middle::mem_categorization::Typer;
|
||||||
use middle::subst;
|
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
use middle::ty_fold::TypeFoldable;
|
|
||||||
use middle::ty_fold;
|
|
||||||
use util::ppaux::{ty_to_string};
|
use util::ppaux::{ty_to_string};
|
||||||
use util::ppaux::UserString;
|
use util::ppaux::UserString;
|
||||||
|
|
||||||
use syntax::ast::*;
|
use syntax::ast::*;
|
||||||
use syntax::attr;
|
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::print::pprust::{expr_to_string, ident_to_string};
|
use syntax::print::pprust::{expr_to_string, ident_to_string};
|
||||||
use syntax::visit::Visitor;
|
use syntax::visit::Visitor;
|
||||||
|
@ -48,10 +44,6 @@ impl<'a, 'tcx, 'v> Visitor<'v> for Context<'a, 'tcx> {
|
||||||
check_ty(self, t);
|
check_ty(self, t);
|
||||||
}
|
}
|
||||||
|
|
||||||
fn visit_item(&mut self, i: &Item) {
|
|
||||||
check_item(self, i);
|
|
||||||
}
|
|
||||||
|
|
||||||
fn visit_pat(&mut self, p: &Pat) {
|
fn visit_pat(&mut self, p: &Pat) {
|
||||||
check_pat(self, p);
|
check_pat(self, p);
|
||||||
}
|
}
|
||||||
|
@ -65,79 +57,6 @@ pub fn check_crate(tcx: &ty::ctxt) {
|
||||||
tcx.sess.abort_if_errors();
|
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
|
// Yields the appropriate function to check the kind of closed over
|
||||||
// variables. `id` is the NodeId for some expression that creates the
|
// variables. `id` is the NodeId for some expression that creates the
|
||||||
// closure.
|
// closure.
|
||||||
|
|
|
@ -69,6 +69,9 @@ pub enum ObligationCauseCode {
|
||||||
/// Obligation incurred due to an object cast.
|
/// Obligation incurred due to an object cast.
|
||||||
ObjectCastObligation(/* Object type */ ty::t),
|
ObjectCastObligation(/* Object type */ ty::t),
|
||||||
|
|
||||||
|
/// To implement drop, type must be sendable.
|
||||||
|
DropTrait,
|
||||||
|
|
||||||
/// Various cases where expressions must be sized/copy/etc:
|
/// Various cases where expressions must be sized/copy/etc:
|
||||||
AssignmentLhsSized, // L = X implies that L is Sized
|
AssignmentLhsSized, // L = X implies that L is Sized
|
||||||
StructInitializerSized, // S { ... } must be Sized
|
StructInitializerSized, // S { ... } must be Sized
|
||||||
|
|
|
@ -390,5 +390,13 @@ fn note_obligation_cause(fcx: &FnCtxt,
|
||||||
obligation.cause.span,
|
obligation.cause.span,
|
||||||
"structs must have a statically known size to be initialized");
|
"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");
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,6 +8,7 @@
|
||||||
// option. This file may not be copied, modified, or distributed
|
// option. This file may not be copied, modified, or distributed
|
||||||
// except according to those terms.
|
// except according to those terms.
|
||||||
|
|
||||||
|
use middle::subst;
|
||||||
use middle::subst::{Subst};
|
use middle::subst::{Subst};
|
||||||
use middle::traits;
|
use middle::traits;
|
||||||
use middle::ty;
|
use middle::ty;
|
||||||
|
@ -21,6 +22,7 @@ use util::ppaux::Repr;
|
||||||
use std::collections::HashSet;
|
use std::collections::HashSet;
|
||||||
use syntax::ast;
|
use syntax::ast;
|
||||||
use syntax::ast_util::{local_def};
|
use syntax::ast_util::{local_def};
|
||||||
|
use syntax::attr;
|
||||||
use syntax::codemap::Span;
|
use syntax::codemap::Span;
|
||||||
use syntax::visit;
|
use syntax::visit;
|
||||||
use syntax::visit::Visitor;
|
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);
|
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
|
// We are stricter on the trait-ref in an impl than the
|
||||||
// self-type. In particular, we enforce region
|
// self-type. In particular, we enforce region
|
||||||
// relationships. The reason for this is that (at least
|
// 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
|
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");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
|
@ -16,7 +16,27 @@ struct Foo {
|
||||||
}
|
}
|
||||||
|
|
||||||
impl Drop for 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) {
|
fn drop(&mut self) {
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
Loading…
Add table
Reference in a new issue