about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2015-03-04 15:23:17 -0500
committerNiko Matsakis <niko@alum.mit.edu>2015-03-06 18:27:50 -0500
commit2e216896e4778738b4ed01e427f711f3a0b2c44c (patch)
tree171983f2556f569ce8c9a5219bc6227d79432aef
parentdbec033e29417ab01bae5749b58f8866b300f005 (diff)
downloadrust-2e216896e4778738b4ed01e427f711f3a0b2c44c.tar.gz
rust-2e216896e4778738b4ed01e427f711f3a0b2c44c.zip
Add stricter orphan rules for cross-crate impls of default traits.
-rw-r--r--src/librustc_typeck/coherence/orphan.rs37
-rw-r--r--src/test/auxiliary/typeck-default-trait-impl-cross-crate-coherence-lib.rs17
-rw-r--r--src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs34
3 files changed, 87 insertions, 1 deletions
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 95dafccd866..fc49a555ad3 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -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
diff --git a/src/test/auxiliary/typeck-default-trait-impl-cross-crate-coherence-lib.rs b/src/test/auxiliary/typeck-default-trait-impl-cross-crate-coherence-lib.rs
new file mode 100644
index 00000000000..579b9b01925
--- /dev/null
+++ b/src/test/auxiliary/typeck-default-trait-impl-cross-crate-coherence-lib.rs
@@ -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 .. { }
diff --git a/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs b/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs
new file mode 100644
index 00000000000..bcc01d1a0a7
--- /dev/null
+++ b/src/test/compile-fail/typeck-default-trait-impl-cross-crate-coherence.rs
@@ -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() { }