Add stricter orphan rules for cross-crate impls of default traits.

This commit is contained in:
Niko Matsakis 2015-03-04 15:23:17 -05:00
parent dbec033e29
commit 2e216896e4
3 changed files with 87 additions and 1 deletions

View file

@ -69,7 +69,8 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
ast::ItemImpl(_, _, _, Some(_), _, _) => {
// "Trait" impl
debug!("coherence2::orphan check: trait impl {}", item.repr(self.tcx));
let trait_def_id = ty::impl_trait_ref(self.tcx, def_id).unwrap().def_id;
let trait_ref = ty::impl_trait_ref(self.tcx, def_id).unwrap();
let trait_def_id = trait_ref.def_id;
match traits::orphan_check(self.tcx, def_id) {
Ok(()) => { }
Err(traits::OrphanCheckErr::NoLocalInputType) => {
@ -92,6 +93,40 @@ impl<'cx, 'tcx,'v> visit::Visitor<'v> for OrphanChecker<'cx, 'tcx> {
}
}
}
// Impls of a defaulted trait face additional rules.
debug!("trait_ref={} trait_def_id={} trait_has_default_impl={}",
trait_ref.repr(self.tcx),
trait_def_id.repr(self.tcx),
ty::trait_has_default_impl(self.tcx, trait_def_id));
if
ty::trait_has_default_impl(self.tcx, trait_def_id) &&
trait_def_id.krate != ast::LOCAL_CRATE
{
let self_ty = trait_ref.self_ty();
match self_ty.sty {
ty::ty_struct(self_def_id, _) | ty::ty_enum(self_def_id, _) => {
// The orphan check often rules this out,
// but not always. For example, the orphan
// check would accept `impl Send for
// Box<SomethingLocal>`, but we want to
// forbid that.
if self_def_id.krate != ast::LOCAL_CRATE {
self.tcx.sess.span_err(
item.span,
"cross-crate traits with a default impl \
can only be implemented for a struct/enum type \
defined in the current crate");
}
}
_ => {
self.tcx.sess.span_err(
item.span,
"cross-crate traits with a default impl \
can only be implemented for a struct or enum type");
}
}
}
}
ast::ItemDefaultImpl(..) => {
// "Trait" impl

View file

@ -0,0 +1,17 @@
// Copyright 2015 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.
#![feature(optin_builtin_traits)]
#![crate_type = "rlib"]
use std::marker::MarkerTrait;
pub trait DefaultedTrait : MarkerTrait { }
impl DefaultedTrait for .. { }

View file

@ -0,0 +1,34 @@
// Copyright 2015 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.
// aux-build:typeck-default-trait-impl-cross-crate-coherence-lib.rs
// Test that we do not consider associated types to be sendable without
// some applicable trait bound (and we don't ICE).
#![feature(optin_builtin_traits)]
extern crate "typeck-default-trait-impl-cross-crate-coherence-lib" as lib;
use lib::DefaultedTrait;
struct A;
impl DefaultedTrait for (A,) { }
//~^ ERROR can only be implemented for a struct or enum type
struct B;
impl !DefaultedTrait for (B,) { }
//~^ ERROR can only be implemented for a struct or enum type
struct C;
impl DefaultedTrait for Box<C> { }
//~^ ERROR can only be implemented for a struct or enum type
fn main() { }