1
Fork 0

Auto merge of #38152 - arielb1:special-copy, r=nikomatsakis

Fix associated types in copy implementations

Fixes an ICE and an error in checking copy implementations.

r? @nikomatsakis
This commit is contained in:
bors 2017-01-05 13:05:30 +00:00
commit 74e5b7d96a
8 changed files with 455 additions and 437 deletions

View file

@ -234,12 +234,10 @@ pub trait Unsize<T: ?Sized> {
/// Generalizing the latter case, any type implementing [`Drop`] can't be `Copy`, because it's
/// managing some resource besides its own [`size_of::<T>()`] bytes.
///
/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get a
/// compile-time error. Specifically, with structs you'll get [E0204] and with enums you'll get
/// [E0205].
/// If you try to implement `Copy` on a struct or enum containing non-`Copy` data, you will get
/// the error [E0204].
///
/// [E0204]: ../../error-index.html#E0204
/// [E0205]: ../../error-index.html#E0205
///
/// ## When *should* my type be `Copy`?
///

View file

@ -15,7 +15,7 @@ use hir::map::DefPathData;
use infer::InferCtxt;
use hir::map as ast_map;
use traits::{self, Reveal};
use ty::{self, Ty, AdtKind, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
use ty::{self, Ty, TyCtxt, TypeAndMut, TypeFlags, TypeFoldable};
use ty::{Disr, ParameterEnvironment};
use ty::fold::TypeVisitor;
use ty::layout::{Layout, LayoutError};
@ -120,9 +120,8 @@ impl IntTypeExt for attr::IntType {
#[derive(Copy, Clone)]
pub enum CopyImplementationError {
InfrigingField(Name),
InfrigingVariant(Name),
pub enum CopyImplementationError<'tcx> {
InfrigingField(&'tcx ty::FieldDef),
NotAnAdt,
HasDestructor
}
@ -145,37 +144,30 @@ pub enum Representability {
impl<'tcx> ParameterEnvironment<'tcx> {
pub fn can_type_implement_copy<'a>(&self, tcx: TyCtxt<'a, 'tcx, 'tcx>,
self_type: Ty<'tcx>, span: Span)
-> Result<(),CopyImplementationError> {
-> Result<(), CopyImplementationError> {
// FIXME: (@jroesch) float this code up
tcx.infer_ctxt(None, Some(self.clone()), Reveal::ExactMatch).enter(|infcx| {
let adt = match self_type.sty {
ty::TyAdt(adt, substs) => match adt.adt_kind() {
AdtKind::Struct | AdtKind::Union => {
for field in adt.all_fields() {
let field_ty = field.ty(tcx, substs);
if infcx.type_moves_by_default(field_ty, span) {
return Err(CopyImplementationError::InfrigingField(
field.name))
}
}
adt
}
AdtKind::Enum => {
for variant in &adt.variants {
for field in &variant.fields {
let field_ty = field.ty(tcx, substs);
if infcx.type_moves_by_default(field_ty, span) {
return Err(CopyImplementationError::InfrigingVariant(
variant.name))
}
}
}
adt
}
},
tcx.infer_ctxt(None, Some(self.clone()), Reveal::NotSpecializable).enter(|infcx| {
let (adt, substs) = match self_type.sty {
ty::TyAdt(adt, substs) => (adt, substs),
_ => return Err(CopyImplementationError::NotAnAdt)
};
let field_implements_copy = |field: &ty::FieldDef| {
let cause = traits::ObligationCause::dummy();
match traits::fully_normalize(&infcx, cause, &field.ty(tcx, substs)) {
Ok(ty) => !infcx.type_moves_by_default(ty, span),
Err(..) => false
}
};
for variant in &adt.variants {
for field in &variant.fields {
if !field_implements_copy(field) {
return Err(CopyImplementationError::InfrigingField(field));
}
}
}
if adt.has_dtor() {
return Err(CopyImplementationError::HasDestructor);
}

View file

@ -0,0 +1,349 @@
// Copyright 2016 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.
//! Check properties that are required by built-in traits and set
//! up data structures required by type-checking/translation.
use rustc::middle::free_region::FreeRegionMap;
use rustc::middle::lang_items::UnsizeTraitLangItem;
use rustc::traits::{self, ObligationCause, Reveal};
use rustc::ty::{self, Ty, TyCtxt};
use rustc::ty::ParameterEnvironment;
use rustc::ty::TypeFoldable;
use rustc::ty::subst::Subst;
use rustc::ty::util::CopyImplementationError;
use rustc::infer;
use rustc::hir::def_id::DefId;
use rustc::hir::map as hir_map;
use rustc::hir::{self, ItemImpl};
pub fn check<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>) {
check_trait(tcx, tcx.lang_items.drop_trait(), visit_implementation_of_drop);
check_trait(tcx, tcx.lang_items.copy_trait(), visit_implementation_of_copy);
check_trait(
tcx,
tcx.lang_items.coerce_unsized_trait(),
visit_implementation_of_coerce_unsized);
}
fn check_trait<'a, 'tcx, F>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
trait_def_id: Option<DefId>,
mut f: F)
where F: FnMut(TyCtxt<'a, 'tcx, 'tcx>, DefId, DefId)
{
if let Some(trait_def_id) = trait_def_id {
let mut impls = vec![];
tcx.lookup_trait_def(trait_def_id).for_each_impl(tcx, |did| {
impls.push(did);
});
impls.sort();
for impl_def_id in impls {
f(tcx, trait_def_id, impl_def_id);
}
}
}
fn visit_implementation_of_drop<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
_drop_did: DefId,
impl_did: DefId) {
let items = tcx.associated_item_def_ids(impl_did);
if items.is_empty() {
// We'll error out later. For now, just don't ICE.
return;
}
let method_def_id = items[0];
let self_type = tcx.item_type(impl_did);
match self_type.sty {
ty::TyAdt(type_def, _) => {
type_def.set_destructor(method_def_id);
}
_ => {
// Destructors only work on nominal types.
if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) {
match tcx.map.find(impl_node_id) {
Some(hir_map::NodeItem(item)) => {
let span = match item.node {
ItemImpl(.., ref ty, _) => ty.span,
_ => item.span,
};
struct_span_err!(tcx.sess,
span,
E0120,
"the Drop trait may only be implemented on \
structures")
.span_label(span, &format!("implementing Drop requires a struct"))
.emit();
}
_ => {
bug!("didn't find impl in ast map");
}
}
} else {
bug!("found external impl of Drop trait on \
something other than a struct");
}
}
}
}
fn visit_implementation_of_copy<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
_copy_did: DefId,
impl_did: DefId) {
debug!("visit_implementation_of_copy: impl_did={:?}", impl_did);
let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
n
} else {
debug!("visit_implementation_of_copy(): impl not in this \
crate");
return;
};
let self_type = tcx.item_type(impl_did);
debug!("visit_implementation_of_copy: self_type={:?} (bound)",
self_type);
let span = tcx.map.span(impl_node_id);
let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
let self_type = self_type.subst(tcx, &param_env.free_substs);
assert!(!self_type.has_escaping_regions());
debug!("visit_implementation_of_copy: self_type={:?} (free)",
self_type);
match param_env.can_type_implement_copy(tcx, self_type, span) {
Ok(()) => {}
Err(CopyImplementationError::InfrigingField(field)) => {
let item = tcx.map.expect_item(impl_node_id);
let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
tr.path.span
} else {
span
};
struct_span_err!(tcx.sess,
span,
E0204,
"the trait `Copy` may not be implemented for this type")
.span_label(
tcx.def_span(field.did),
&"this field does not implement `Copy`")
.emit()
}
Err(CopyImplementationError::NotAnAdt) => {
let item = tcx.map.expect_item(impl_node_id);
let span = if let ItemImpl(.., ref ty, _) = item.node {
ty.span
} else {
span
};
struct_span_err!(tcx.sess,
span,
E0206,
"the trait `Copy` may not be implemented for this type")
.span_label(span, &format!("type is not a structure or enumeration"))
.emit();
}
Err(CopyImplementationError::HasDestructor) => {
struct_span_err!(tcx.sess,
span,
E0184,
"the trait `Copy` may not be implemented for this type; the \
type has a destructor")
.span_label(span, &format!("Copy not allowed on types with destructors"))
.emit();
}
}
}
fn visit_implementation_of_coerce_unsized<'a, 'tcx>(tcx: TyCtxt<'a, 'tcx, 'tcx>,
coerce_unsized_trait: DefId,
impl_did: DefId) {
debug!("visit_implementation_of_coerce_unsized: impl_did={:?}",
impl_did);
let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
Ok(id) => id,
Err(err) => {
tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
}
};
let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
n
} else {
debug!("visit_implementation_of_coerce_unsized(): impl not \
in this crate");
return;
};
let source = tcx.item_type(impl_did);
let trait_ref = tcx.impl_trait_ref(impl_did).unwrap();
let target = trait_ref.substs.type_at(1);
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (bound)",
source,
target);
let span = tcx.map.span(impl_node_id);
let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
let source = source.subst(tcx, &param_env.free_substs);
let target = target.subst(tcx, &param_env.free_substs);
assert!(!source.has_escaping_regions());
debug!("visit_implementation_of_coerce_unsized: {:?} -> {:?} (free)",
source,
target);
tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
let cause = ObligationCause::misc(span, impl_node_id);
let check_mutbl = |mt_a: ty::TypeAndMut<'tcx>,
mt_b: ty::TypeAndMut<'tcx>,
mk_ptr: &Fn(Ty<'tcx>) -> Ty<'tcx>| {
if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
infcx.report_mismatched_types(&cause,
mk_ptr(mt_b.ty),
target,
ty::error::TypeError::Mutability)
.emit();
}
(mt_a.ty, mt_b.ty, unsize_trait, None)
};
let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
(&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
(&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
}
(&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
(&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
}
(&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b)) if def_a.is_struct() &&
def_b.is_struct() => {
if def_a != def_b {
let source_path = tcx.item_path_str(def_a.did);
let target_path = tcx.item_path_str(def_b.did);
span_err!(tcx.sess,
span,
E0377,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with the same \
definition; expected {}, found {}",
source_path,
target_path);
return;
}
let fields = &def_a.struct_variant().fields;
let diff_fields = fields.iter()
.enumerate()
.filter_map(|(i, f)| {
let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
if tcx.item_type(f.did).is_phantom_data() {
// Ignore PhantomData fields
return None;
}
// Ignore fields that aren't significantly changed
if let Ok(ok) = infcx.sub_types(false, &cause, b, a) {
if ok.obligations.is_empty() {
return None;
}
}
// Collect up all fields that were significantly changed
// i.e. those that contain T in coerce_unsized T -> U
Some((i, a, b))
})
.collect::<Vec<_>>();
if diff_fields.is_empty() {
span_err!(tcx.sess,
span,
E0374,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with one field \
being coerced, none found");
return;
} else if diff_fields.len() > 1 {
let item = tcx.map.expect_item(impl_node_id);
let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
t.path.span
} else {
tcx.map.span(impl_node_id)
};
let mut err = struct_span_err!(tcx.sess,
span,
E0375,
"implementing the trait \
`CoerceUnsized` requires multiple \
coercions");
err.note("`CoerceUnsized` may only be implemented for \
a coercion between structures with one field being coerced");
err.note(&format!("currently, {} fields need coercions: {}",
diff_fields.len(),
diff_fields.iter()
.map(|&(i, a, b)| {
format!("{} ({} to {})", fields[i].name, a, b)
})
.collect::<Vec<_>>()
.join(", ")));
err.span_label(span, &format!("requires multiple coercions"));
err.emit();
return;
}
let (i, a, b) = diff_fields[0];
let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
(a, b, coerce_unsized_trait, Some(kind))
}
_ => {
span_err!(tcx.sess,
span,
E0376,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures");
return;
}
};
let mut fulfill_cx = traits::FulfillmentContext::new();
// Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_node_id);
let predicate = tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
fulfill_cx.register_predicate_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied.
if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(&errors);
}
// Finally, resolve all regions.
let mut free_regions = FreeRegionMap::new();
free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
.caller_bounds);
infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
if let Some(kind) = kind {
tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
}
});
}

View file

@ -16,45 +16,33 @@
// mappings. That mapping code resides here.
use hir::def_id::DefId;
use middle::lang_items::UnsizeTraitLangItem;
use rustc::ty::subst::Subst;
use rustc::ty::{self, TyCtxt, TypeFoldable};
use rustc::traits::{self, ObligationCause, Reveal};
use rustc::ty::ParameterEnvironment;
use rustc::ty::{Ty, TyBool, TyChar, TyError};
use rustc::ty::{TyParam, TyRawPtr};
use rustc::ty::{TyRef, TyAdt, TyDynamic, TyNever, TyTuple};
use rustc::ty::{TyStr, TyArray, TySlice, TyFloat, TyInfer, TyInt};
use rustc::ty::{TyUint, TyClosure, TyBox, TyFnDef, TyFnPtr};
use rustc::ty::{TyProjection, TyAnon};
use rustc::ty::util::CopyImplementationError;
use middle::free_region::FreeRegionMap;
use CrateCtxt;
use rustc::infer::{self, InferCtxt};
use syntax_pos::Span;
use rustc::dep_graph::DepNode;
use rustc::hir::map as hir_map;
use rustc::hir::itemlikevisit::ItemLikeVisitor;
use rustc::hir::{Item, ItemImpl};
use rustc::hir;
mod builtin;
mod orphan;
mod overlap;
mod unsafety;
struct CoherenceChecker<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
crate_context: &'a CrateCtxt<'a, 'gcx>,
inference_context: InferCtxt<'a, 'gcx, 'tcx>,
struct CoherenceChecker<'a, 'tcx: 'a> {
tcx: TyCtxt<'a, 'tcx, 'tcx>,
}
struct CoherenceCheckVisitor<'a, 'gcx: 'a + 'tcx, 'tcx: 'a> {
cc: &'a CoherenceChecker<'a, 'gcx, 'tcx>,
}
impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx, 'tcx> {
impl<'a, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceChecker<'a, 'tcx> {
fn visit_item(&mut self, item: &Item) {
if let ItemImpl(..) = item.node {
self.cc.check_implementation(item)
self.check_implementation(item)
}
}
@ -65,7 +53,7 @@ impl<'a, 'gcx, 'tcx, 'v> ItemLikeVisitor<'v> for CoherenceCheckVisitor<'a, 'gcx,
}
}
impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
impl<'a, 'tcx> CoherenceChecker<'a, 'tcx> {
// Returns the def ID of the base type, if there is one.
fn get_base_type_def_id(&self, span: Span, ty: Ty<'tcx>) -> Option<DefId> {
match ty.sty {
@ -73,7 +61,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
TyDynamic(ref t, ..) => t.principal().map(|p| p.def_id()),
TyBox(_) => self.inference_context.tcx.lang_items.owned_box(),
TyBox(_) => self.tcx.lang_items.owned_box(),
TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) | TyStr | TyArray(..) |
TySlice(..) | TyFnDef(..) | TyFnPtr(_) | TyTuple(..) | TyParam(..) | TyError |
@ -89,36 +77,22 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
}
}
fn check(&self) {
fn check(&mut self) {
// Check implementations and traits. This populates the tables
// containing the inherent methods and extension methods. It also
// builds up the trait inheritance table.
self.crate_context.tcx.visit_all_item_likes_in_krate(
DepNode::CoherenceCheckImpl,
&mut CoherenceCheckVisitor { cc: self });
// Populate the table of destructors. It might seem a bit strange to
// do this here, but it's actually the most convenient place, since
// the coherence tables contain the trait -> type mappings.
self.populate_destructors();
// Check to make sure implementations of `Copy` are legal.
self.check_implementations_of_copy();
// Check to make sure implementations of `CoerceUnsized` are legal
// and collect the necessary information from them.
self.check_implementations_of_coerce_unsized();
self.tcx.visit_all_item_likes_in_krate(DepNode::CoherenceCheckImpl, self);
}
fn check_implementation(&self, item: &Item) {
let tcx = self.crate_context.tcx;
let tcx = self.tcx;
let impl_did = tcx.map.local_def_id(item.id);
let self_type = tcx.item_type(impl_did);
// If there are no traits, then this implementation must have a
// base type.
if let Some(trait_ref) = self.crate_context.tcx.impl_trait_ref(impl_did) {
if let Some(trait_ref) = self.tcx.impl_trait_ref(impl_did) {
debug!("(checking implementation) adding impl for trait '{:?}', item '{}'",
trait_ref,
item.name);
@ -129,9 +103,7 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
return;
}
enforce_trait_manually_implementable(self.crate_context.tcx,
item.span,
trait_ref.def_id);
enforce_trait_manually_implementable(self.tcx, item.span, trait_ref.def_id);
self.add_trait_impl(trait_ref, impl_did);
} else {
// Skip inherent impls where the self type is an error
@ -150,348 +122,15 @@ impl<'a, 'gcx, 'tcx> CoherenceChecker<'a, 'gcx, 'tcx> {
}
fn add_inherent_impl(&self, base_def_id: DefId, impl_def_id: DefId) {
let tcx = self.crate_context.tcx;
tcx.inherent_impls.borrow_mut().push(base_def_id, impl_def_id);
self.tcx.inherent_impls.borrow_mut().push(base_def_id, impl_def_id);
}
fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'gcx>, impl_def_id: DefId) {
fn add_trait_impl(&self, impl_trait_ref: ty::TraitRef<'tcx>, impl_def_id: DefId) {
debug!("add_trait_impl: impl_trait_ref={:?} impl_def_id={:?}",
impl_trait_ref,
impl_def_id);
let trait_def = self.crate_context.tcx.lookup_trait_def(impl_trait_ref.def_id);
trait_def.record_local_impl(self.crate_context.tcx, impl_def_id, impl_trait_ref);
}
// Destructors
//
fn populate_destructors(&self) {
let tcx = self.crate_context.tcx;
let drop_trait = match tcx.lang_items.drop_trait() {
Some(id) => id,
None => return,
};
tcx.populate_implementations_for_trait_if_necessary(drop_trait);
let drop_trait = tcx.lookup_trait_def(drop_trait);
drop_trait.for_each_impl(tcx, |impl_did| {
let items = tcx.associated_item_def_ids(impl_did);
if items.is_empty() {
// We'll error out later. For now, just don't ICE.
return;
}
let method_def_id = items[0];
let self_type = tcx.item_type(impl_did);
match self_type.sty {
ty::TyAdt(type_def, _) => {
type_def.set_destructor(method_def_id);
}
_ => {
// Destructors only work on nominal types.
if let Some(impl_node_id) = tcx.map.as_local_node_id(impl_did) {
match tcx.map.find(impl_node_id) {
Some(hir_map::NodeItem(item)) => {
let span = match item.node {
ItemImpl(.., ref ty, _) => ty.span,
_ => item.span,
};
struct_span_err!(tcx.sess,
span,
E0120,
"the Drop trait may only be implemented on \
structures")
.span_label(span,
&format!("implementing Drop requires a struct"))
.emit();
}
_ => {
bug!("didn't find impl in ast map");
}
}
} else {
bug!("found external impl of Drop trait on \
something other than a struct");
}
}
}
});
}
/// Ensures that implementations of the built-in trait `Copy` are legal.
fn check_implementations_of_copy(&self) {
let tcx = self.crate_context.tcx;
let copy_trait = match tcx.lang_items.copy_trait() {
Some(id) => id,
None => return,
};
tcx.populate_implementations_for_trait_if_necessary(copy_trait);
let copy_trait = tcx.lookup_trait_def(copy_trait);
copy_trait.for_each_impl(tcx, |impl_did| {
debug!("check_implementations_of_copy: impl_did={:?}", impl_did);
let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
n
} else {
debug!("check_implementations_of_copy(): impl not in this \
crate");
return;
};
let self_type = tcx.item_type(impl_did);
debug!("check_implementations_of_copy: self_type={:?} (bound)",
self_type);
let span = tcx.map.span(impl_node_id);
let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
let self_type = self_type.subst(tcx, &param_env.free_substs);
assert!(!self_type.has_escaping_regions());
debug!("check_implementations_of_copy: self_type={:?} (free)",
self_type);
match param_env.can_type_implement_copy(tcx, self_type, span) {
Ok(()) => {}
Err(CopyImplementationError::InfrigingField(name)) => {
struct_span_err!(tcx.sess,
span,
E0204,
"the trait `Copy` may not be implemented for this type")
.span_label(span, &format!("field `{}` does not implement `Copy`", name))
.emit()
}
Err(CopyImplementationError::InfrigingVariant(name)) => {
let item = tcx.map.expect_item(impl_node_id);
let span = if let ItemImpl(.., Some(ref tr), _, _) = item.node {
tr.path.span
} else {
span
};
struct_span_err!(tcx.sess,
span,
E0205,
"the trait `Copy` may not be implemented for this type")
.span_label(span,
&format!("variant `{}` does not implement `Copy`", name))
.emit()
}
Err(CopyImplementationError::NotAnAdt) => {
let item = tcx.map.expect_item(impl_node_id);
let span = if let ItemImpl(.., ref ty, _) = item.node {
ty.span
} else {
span
};
struct_span_err!(tcx.sess,
span,
E0206,
"the trait `Copy` may not be implemented for this type")
.span_label(span, &format!("type is not a structure or enumeration"))
.emit();
}
Err(CopyImplementationError::HasDestructor) => {
struct_span_err!(tcx.sess,
span,
E0184,
"the trait `Copy` may not be implemented for this type; the \
type has a destructor")
.span_label(span, &format!("Copy not allowed on types with destructors"))
.emit();
}
}
});
}
/// Process implementations of the built-in trait `CoerceUnsized`.
fn check_implementations_of_coerce_unsized(&self) {
let tcx = self.crate_context.tcx;
let coerce_unsized_trait = match tcx.lang_items.coerce_unsized_trait() {
Some(id) => id,
None => return,
};
let unsize_trait = match tcx.lang_items.require(UnsizeTraitLangItem) {
Ok(id) => id,
Err(err) => {
tcx.sess.fatal(&format!("`CoerceUnsized` implementation {}", err));
}
};
let trait_def = tcx.lookup_trait_def(coerce_unsized_trait);
trait_def.for_each_impl(tcx, |impl_did| {
debug!("check_implementations_of_coerce_unsized: impl_did={:?}",
impl_did);
let impl_node_id = if let Some(n) = tcx.map.as_local_node_id(impl_did) {
n
} else {
debug!("check_implementations_of_coerce_unsized(): impl not \
in this crate");
return;
};
let source = tcx.item_type(impl_did);
let trait_ref = self.crate_context.tcx.impl_trait_ref(impl_did).unwrap();
let target = trait_ref.substs.type_at(1);
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (bound)",
source,
target);
let span = tcx.map.span(impl_node_id);
let param_env = ParameterEnvironment::for_item(tcx, impl_node_id);
let source = source.subst(tcx, &param_env.free_substs);
let target = target.subst(tcx, &param_env.free_substs);
assert!(!source.has_escaping_regions());
debug!("check_implementations_of_coerce_unsized: {:?} -> {:?} (free)",
source,
target);
tcx.infer_ctxt(None, Some(param_env), Reveal::ExactMatch).enter(|infcx| {
let cause = ObligationCause::misc(span, impl_node_id);
let check_mutbl = |mt_a: ty::TypeAndMut<'gcx>,
mt_b: ty::TypeAndMut<'gcx>,
mk_ptr: &Fn(Ty<'gcx>) -> Ty<'gcx>| {
if (mt_a.mutbl, mt_b.mutbl) == (hir::MutImmutable, hir::MutMutable) {
infcx.report_mismatched_types(&cause,
mk_ptr(mt_b.ty),
target,
ty::error::TypeError::Mutability).emit();
}
(mt_a.ty, mt_b.ty, unsize_trait, None)
};
let (source, target, trait_def_id, kind) = match (&source.sty, &target.sty) {
(&ty::TyBox(a), &ty::TyBox(b)) => (a, b, unsize_trait, None),
(&ty::TyRef(r_a, mt_a), &ty::TyRef(r_b, mt_b)) => {
infcx.sub_regions(infer::RelateObjectBound(span), r_b, r_a);
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ref(r_b, ty))
}
(&ty::TyRef(_, mt_a), &ty::TyRawPtr(mt_b)) |
(&ty::TyRawPtr(mt_a), &ty::TyRawPtr(mt_b)) => {
check_mutbl(mt_a, mt_b, &|ty| tcx.mk_imm_ptr(ty))
}
(&ty::TyAdt(def_a, substs_a), &ty::TyAdt(def_b, substs_b))
if def_a.is_struct() && def_b.is_struct() => {
if def_a != def_b {
let source_path = tcx.item_path_str(def_a.did);
let target_path = tcx.item_path_str(def_b.did);
span_err!(tcx.sess,
span,
E0377,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with the same \
definition; expected {}, found {}",
source_path,
target_path);
return;
}
let fields = &def_a.struct_variant().fields;
let diff_fields = fields.iter()
.enumerate()
.filter_map(|(i, f)| {
let (a, b) = (f.ty(tcx, substs_a), f.ty(tcx, substs_b));
if tcx.item_type(f.did).is_phantom_data() {
// Ignore PhantomData fields
return None;
}
// Ignore fields that aren't significantly changed
if let Ok(ok) = infcx.sub_types(false, &cause, b, a) {
if ok.obligations.is_empty() {
return None;
}
}
// Collect up all fields that were significantly changed
// i.e. those that contain T in coerce_unsized T -> U
Some((i, a, b))
})
.collect::<Vec<_>>();
if diff_fields.is_empty() {
span_err!(tcx.sess,
span,
E0374,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures with one field \
being coerced, none found");
return;
} else if diff_fields.len() > 1 {
let item = tcx.map.expect_item(impl_node_id);
let span = if let ItemImpl(.., Some(ref t), _, _) = item.node {
t.path.span
} else {
tcx.map.span(impl_node_id)
};
let mut err = struct_span_err!(tcx.sess,
span,
E0375,
"implementing the trait \
`CoerceUnsized` requires multiple \
coercions");
err.note("`CoerceUnsized` may only be implemented for \
a coercion between structures with one field being coerced");
err.note(&format!("currently, {} fields need coercions: {}",
diff_fields.len(),
diff_fields.iter()
.map(|&(i, a, b)| {
format!("{} ({} to {})", fields[i].name, a, b)
})
.collect::<Vec<_>>()
.join(", ")));
err.span_label(span, &format!("requires multiple coercions"));
err.emit();
return;
}
let (i, a, b) = diff_fields[0];
let kind = ty::adjustment::CustomCoerceUnsized::Struct(i);
(a, b, coerce_unsized_trait, Some(kind))
}
_ => {
span_err!(tcx.sess,
span,
E0376,
"the trait `CoerceUnsized` may only be implemented \
for a coercion between structures");
return;
}
};
let mut fulfill_cx = traits::FulfillmentContext::new();
// Register an obligation for `A: Trait<B>`.
let cause = traits::ObligationCause::misc(span, impl_node_id);
let predicate =
tcx.predicate_for_trait_def(cause, trait_def_id, 0, source, &[target]);
fulfill_cx.register_predicate_obligation(&infcx, predicate);
// Check that all transitive obligations are satisfied.
if let Err(errors) = fulfill_cx.select_all_or_error(&infcx) {
infcx.report_fulfillment_errors(&errors);
}
// Finally, resolve all regions.
let mut free_regions = FreeRegionMap::new();
free_regions.relate_free_regions_from_predicates(&infcx.parameter_environment
.caller_bounds);
infcx.resolve_regions_and_report_errors(&free_regions, impl_node_id);
if let Some(kind) = kind {
tcx.custom_coerce_unsized_kinds.borrow_mut().insert(impl_did, kind);
}
});
});
let trait_def = self.tcx.lookup_trait_def(impl_trait_ref.def_id);
trait_def.record_local_impl(self.tcx, impl_def_id, impl_trait_ref);
}
}
@ -524,14 +163,9 @@ fn enforce_trait_manually_implementable(tcx: TyCtxt, sp: Span, trait_def_id: Def
pub fn check_coherence(ccx: &CrateCtxt) {
let _task = ccx.tcx.dep_graph.in_task(DepNode::Coherence);
ccx.tcx.infer_ctxt(None, None, Reveal::ExactMatch).enter(|infcx| {
CoherenceChecker {
crate_context: ccx,
inference_context: infcx,
}
.check();
});
CoherenceChecker { tcx: ccx.tcx }.check();
unsafety::check(ccx.tcx);
orphan::check(ccx.tcx);
overlap::check(ccx.tcx);
builtin::check(ccx.tcx);
}

View file

@ -2300,6 +2300,7 @@ This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this
differs from the behavior for `&T`, which is always `Copy`).
"##,
/*
E0205: r##"
An attempt to implement the `Copy` trait for an enum failed because one of the
variants does not implement `Copy`. To fix this, you must implement `Copy` for
@ -2329,6 +2330,7 @@ enum Foo<'a> {
This fails because `&mut T` is not `Copy`, even when `T` is `Copy` (this
differs from the behavior for `&T`, which is always `Copy`).
"##,
*/
E0206: r##"
You can only implement `Copy` for a struct or enum. Both of the following

View file

@ -8,22 +8,19 @@
// option. This file may not be copied, modified, or distributed
// except according to those terms.
enum Foo {
Bar(Vec<u32>),
Baz,
struct Foo<A: Repr>(<A as Repr>::Data);
impl<A> Copy for Foo<A> where <A as Repr>::Data: Copy { }
impl<A> Clone for Foo<A> where <A as Repr>::Data: Clone {
fn clone(&self) -> Self { Foo(self.0.clone()) }
}
impl Copy for Foo { }
//~^ ERROR the trait `Copy` may not be implemented for this type
//~| NOTE variant `Bar` does not implement `Copy`
trait Repr {
type Data;
}
#[derive(Copy)]
//~^ ERROR the trait `Copy` may not be implemented for this type
//~| NOTE variant `Bar` does not implement `Copy`
//~| NOTE in this expansion of #[derive(Copy)]
enum Foo2<'a> {
Bar(&'a mut bool),
Baz,
impl<A> Repr for A {
type Data = u32;
}
fn main() {

View file

@ -13,16 +13,24 @@ struct Foo {
}
impl Copy for Foo { }
//~^ ERROR E0204
//~| NOTE field `foo` does not implement `Copy`
#[derive(Copy)]
//~^ ERROR E0204
//~| NOTE field `ty` does not implement `Copy`
//~| NOTE in this expansion of #[derive(Copy)]
struct Foo2<'a> {
ty: &'a mut bool,
}
enum EFoo {
Bar { x: Vec<u32> },
Baz,
}
impl Copy for EFoo { }
#[derive(Copy)]
enum EFoo2<'a> {
Bar(&'a mut bool),
Baz,
}
fn main() {
}

View file

@ -0,0 +1,38 @@
error[E0204]: the trait `Copy` may not be implemented for this type
--> $DIR/E0204.rs:15:6
|
12 | foo: Vec<u32>,
| ------------- this field does not implement `Copy`
...
15 | impl Copy for Foo { }
| ^^^^
error[E0204]: the trait `Copy` may not be implemented for this type
--> $DIR/E0204.rs:27:6
|
23 | Bar { x: Vec<u32> },
| ----------- this field does not implement `Copy`
...
27 | impl Copy for EFoo { }
| ^^^^
error[E0204]: the trait `Copy` may not be implemented for this type
--> $DIR/E0204.rs:17:10
|
17 | #[derive(Copy)]
| ^^^^
18 | struct Foo2<'a> {
19 | ty: &'a mut bool,
| ---------------- this field does not implement `Copy`
error[E0204]: the trait `Copy` may not be implemented for this type
--> $DIR/E0204.rs:29:10
|
29 | #[derive(Copy)]
| ^^^^
30 | enum EFoo2<'a> {
31 | Bar(&'a mut bool),
| ------------- this field does not implement `Copy`
error: aborting due to 4 previous errors