about summary refs log tree commit diff
diff options
context:
space:
mode:
authorNiko Matsakis <niko@alum.mit.edu>2014-12-26 03:30:51 -0500
committerNiko Matsakis <niko@alum.mit.edu>2015-01-02 04:06:09 -0500
commitc61a0092bc236c4be4cb691fcd50ff50e91ab0d6 (patch)
tree6cd9026ea34772769ad89d5c78fe4d55cf8b98cb
parent77723d24a831f9a062e210cc964e4849c23df116 (diff)
downloadrust-c61a0092bc236c4be4cb691fcd50ff50e91ab0d6.tar.gz
rust-c61a0092bc236c4be4cb691fcd50ff50e91ab0d6.zip
Fix orphan checking (cc #19470). (This is not a complete fix of #19470 because of the backwards compatibility feature gate.)
This is a [breaking-change]. The new rules require that, for an impl of a trait defined
in some other crate, two conditions must hold:

1. Some type must be local.
2. Every type parameter must appear "under" some local type.

Here are some examples that are legal:

```rust
struct MyStruct<T> { ... }

// Here `T` appears "under' `MyStruct`.
impl<T> Clone for MyStruct<T> { }

// Here `T` appears "under' `MyStruct` as well. Note that it also appears
// elsewhere.
impl<T> Iterator<T> for MyStruct<T> { }
```

Here is an illegal example:

```rust
// Here `U` does not appear "under" `MyStruct` or any other local type.
// We call `U` "uncovered".
impl<T,U> Iterator<U> for MyStruct<T> { }
```

There are a couple of ways to rewrite this last example so that it is
legal:

1. In some cases, the uncovered type parameter (here, `U`) should be converted
   into an associated type. This is however a non-local change that requires access
   to the original trait. Also, associated types are not fully baked.
2. Add `U` as a type parameter of `MyStruct`:
   ```rust
   struct MyStruct<T,U> { ... }
   impl<T,U> Iterator<U> for MyStruct<T,U> { }
   ```
3. Create a newtype wrapper for `U`
   ```rust
   impl<T,U> Iterator<Wrapper<U>> for MyStruct<T,U> { }
   ```

Because associated types are not fully baked, which in the case of the
`Hash` trait makes adhering to this rule impossible, you can
temporarily disable this rule in your crate by using
`#![feature(old_orphan_check)]`. Note that the `old_orphan_check`
feature will be removed before 1.0 is released.
-rw-r--r--src/liballoc/lib.rs3
-rw-r--r--src/libcollections/lib.rs1
-rw-r--r--src/libgraphviz/maybe_owned_vec.rs6
-rw-r--r--src/librustc/lib.rs2
-rw-r--r--src/librustc/middle/traits/coherence.rs153
-rw-r--r--src/librustc/middle/traits/mod.rs11
-rw-r--r--src/librustc_back/lib.rs1
-rw-r--r--src/librustc_borrowck/lib.rs2
-rw-r--r--src/librustc_trans/lib.rs2
-rw-r--r--src/librustc_typeck/coherence/orphan.rs27
-rw-r--r--src/librustdoc/lib.rs1
-rw-r--r--src/libserialize/json.rs2
-rw-r--r--src/libstd/lib.rs1
-rw-r--r--src/libsyntax/feature_gate.rs25
-rw-r--r--src/libsyntax/lib.rs1
-rw-r--r--src/libtest/lib.rs2
-rw-r--r--src/libtime/lib.rs3
-rw-r--r--src/test/compile-fail/opt-out-copy-bad.rs2
-rw-r--r--src/test/run-pass/deriving-encodable-decodable-box.rs2
-rw-r--r--src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs2
-rw-r--r--src/test/run-pass/deriving-global.rs2
-rw-r--r--src/test/run-pass/issue-11881.rs2
-rw-r--r--src/test/run-pass/issue-14021.rs1
-rw-r--r--src/test/run-pass/issue-15734.rs4
-rw-r--r--src/test/run-pass/issue-3743.rs4
-rw-r--r--src/test/run-pass/overloaded-calls-param-vtables.rs4
26 files changed, 171 insertions, 95 deletions
diff --git a/src/liballoc/lib.rs b/src/liballoc/lib.rs
index 61b5d43d1cb..d17a54ce6e5 100644
--- a/src/liballoc/lib.rs
+++ b/src/liballoc/lib.rs
@@ -64,7 +64,8 @@
        html_root_url = "http://doc.rust-lang.org/nightly/")]
 
 #![no_std]
-#![feature(lang_items, phase, unsafe_destructor, default_type_params)]
+#![allow(unknown_features)]
+#![feature(lang_items, phase, unsafe_destructor, default_type_params, old_orphan_check)]
 
 #[phase(plugin, link)]
 extern crate core;
diff --git a/src/libcollections/lib.rs b/src/libcollections/lib.rs
index 688214140c1..b7307cfb7fb 100644
--- a/src/libcollections/lib.rs
+++ b/src/libcollections/lib.rs
@@ -25,6 +25,7 @@
 #![feature(macro_rules, default_type_params, phase, globs)]
 #![feature(unsafe_destructor, slicing_syntax)]
 #![feature(unboxed_closures)]
+#![feature(old_orphan_check)]
 #![no_std]
 
 #[phase(plugin, link)] extern crate core;
diff --git a/src/libgraphviz/maybe_owned_vec.rs b/src/libgraphviz/maybe_owned_vec.rs
index ddda2b38c22..c9943562c88 100644
--- a/src/libgraphviz/maybe_owned_vec.rs
+++ b/src/libgraphviz/maybe_owned_vec.rs
@@ -96,9 +96,9 @@ impl<'a, T: Ord> Ord for MaybeOwnedVector<'a, T> {
 }
 
 #[allow(deprecated)]
-impl<'a, T: PartialEq, Sized? V: AsSlice<T>> Equiv<V> for MaybeOwnedVector<'a, T> {
-    fn equiv(&self, other: &V) -> bool {
-        self.as_slice() == other.as_slice()
+impl<'a, T: PartialEq> Equiv<[T]> for MaybeOwnedVector<'a, T> {
+    fn equiv(&self, other: &[T]) -> bool {
+        self.as_slice() == other
     }
 }
 
diff --git a/src/librustc/lib.rs b/src/librustc/lib.rs
index 3d99a880f68..cdc27244dde 100644
--- a/src/librustc/lib.rs
+++ b/src/librustc/lib.rs
@@ -22,10 +22,12 @@
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/")]
 
+#![allow(unknown_features)]
 #![feature(default_type_params, globs, macro_rules, phase, quote)]
 #![feature(slicing_syntax, unsafe_destructor)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(unboxed_closures)]
+#![feature(old_orphan_check)]
 
 extern crate arena;
 extern crate flate;
diff --git a/src/librustc/middle/traits/coherence.rs b/src/librustc/middle/traits/coherence.rs
index d8b39d92c69..4aff36c2624 100644
--- a/src/librustc/middle/traits/coherence.rs
+++ b/src/librustc/middle/traits/coherence.rs
@@ -14,10 +14,10 @@ use super::SelectionContext;
 use super::{Obligation, ObligationCause};
 use super::util;
 
-use middle::subst;
 use middle::subst::Subst;
 use middle::ty::{mod, Ty};
 use middle::infer::InferCtxt;
+use std::collections::HashSet;
 use std::rc::Rc;
 use syntax::ast;
 use syntax::codemap::DUMMY_SP;
@@ -52,9 +52,21 @@ pub fn impl_can_satisfy(infcx: &InferCtxt,
     selcx.evaluate_impl(impl2_def_id, &obligation)
 }
 
-pub fn impl_is_local(tcx: &ty::ctxt,
-                     impl_def_id: ast::DefId)
-                     -> bool
+#[allow(missing_copy_implementations)]
+pub enum OrphanCheckErr {
+    NoLocalInputType,
+    UncoveredTypeParameter(ty::ParamTy),
+}
+
+/// Checks the coherence orphan rules. `impl_def_id` should be the
+/// def-id of a trait impl. To pass, either the trait must be local, or else
+/// two conditions must be satisfied:
+///
+/// 1. At least one of the input types must involve a local type.
+/// 2. All type parameters must be covered by a local type.
+pub fn orphan_check(tcx: &ty::ctxt,
+                    impl_def_id: ast::DefId)
+                    -> Result<(), OrphanCheckErr>
 {
     debug!("impl_is_local({})", impl_def_id.repr(tcx));
 
@@ -63,20 +75,40 @@ pub fn impl_is_local(tcx: &ty::ctxt,
     let trait_ref = ty::impl_trait_ref(tcx, impl_def_id).unwrap();
     debug!("trait_ref={}", trait_ref.repr(tcx));
 
-    // If the trait is local to the crate, ok.
+    // If the *trait* is local to the crate, ok.
     if trait_ref.def_id.krate == ast::LOCAL_CRATE {
         debug!("trait {} is local to current crate",
                trait_ref.def_id.repr(tcx));
-        return true;
+        return Ok(());
     }
 
-    // Otherwise, at least one of the input types must be local to the
-    // crate.
-    trait_ref.input_types().iter().any(|&t| ty_is_local(tcx, t))
+    // Check condition 1: at least one type must be local.
+    if !trait_ref.input_types().iter().any(|&t| ty_reaches_local(tcx, t)) {
+        return Err(OrphanCheckErr::NoLocalInputType);
+    }
+
+    // Check condition 2: type parameters must be "covered" by a local type.
+    let covered_params: HashSet<_> =
+        trait_ref.input_types().iter()
+                               .flat_map(|&t| type_parameters_covered_by_ty(tcx, t).into_iter())
+                               .collect();
+    let all_params: HashSet<_> =
+        trait_ref.input_types().iter()
+                               .flat_map(|&t| type_parameters_reachable_from_ty(t).into_iter())
+                               .collect();
+    for &param in all_params.difference(&covered_params) {
+        return Err(OrphanCheckErr::UncoveredTypeParameter(param));
+    }
+
+    return Ok(());
+}
+
+fn ty_reaches_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
+    ty.walk().any(|t| ty_is_local_constructor(tcx, t))
 }
 
-pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
-    debug!("ty_is_local({})", ty.repr(tcx));
+fn ty_is_local_constructor<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
+    debug!("ty_is_local_constructor({})", ty.repr(tcx));
 
     match ty.sty {
         ty::ty_bool |
@@ -84,78 +116,33 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
         ty::ty_int(..) |
         ty::ty_uint(..) |
         ty::ty_float(..) |
-        ty::ty_str(..) => {
-            false
-        }
-
-        ty::ty_unboxed_closure(..) => {
-            // This routine is invoked on types specified by users as
-            // part of an impl and hence an unboxed closure type
-            // cannot appear.
-            tcx.sess.bug("ty_is_local applied to unboxed closure type")
-        }
-
+        ty::ty_str(..) |
         ty::ty_bare_fn(..) |
-        ty::ty_closure(..) => {
+        ty::ty_closure(..) |
+        ty::ty_vec(..) |
+        ty::ty_ptr(..) |
+        ty::ty_rptr(..) |
+        ty::ty_tup(..) |
+        ty::ty_param(..) |
+        ty::ty_projection(..) => {
             false
         }
 
-        ty::ty_uniq(t) => {
-            let krate = tcx.lang_items.owned_box().map(|d| d.krate);
-            krate == Some(ast::LOCAL_CRATE) || ty_is_local(tcx, t)
-        }
-
-        ty::ty_vec(t, _) |
-        ty::ty_ptr(ty::mt { ty: t, .. }) |
-        ty::ty_rptr(_, ty::mt { ty: t, .. }) => {
-            ty_is_local(tcx, t)
-        }
-
-        ty::ty_tup(ref ts) => {
-            ts.iter().any(|&t| ty_is_local(tcx, t))
+        ty::ty_enum(def_id, _) |
+        ty::ty_struct(def_id, _) => {
+            def_id.krate == ast::LOCAL_CRATE
         }
 
-        ty::ty_enum(def_id, ref substs) |
-        ty::ty_struct(def_id, ref substs) => {
-            def_id.krate == ast::LOCAL_CRATE || {
-                let variances = ty::item_variances(tcx, def_id);
-                subst::ParamSpace::all().iter().any(|&space| {
-                    substs.types.get_slice(space).iter().enumerate().any(
-                        |(i, &t)| {
-                            match *variances.types.get(space, i) {
-                                ty::Bivariant => {
-                                    // If Foo<T> is bivariant with respect to
-                                    // T, then it doesn't matter whether T is
-                                    // local or not, because `Foo<U>` for any
-                                    // U will be a subtype of T.
-                                    false
-                                }
-                                ty::Contravariant |
-                                ty::Covariant |
-                                ty::Invariant => {
-                                    ty_is_local(tcx, t)
-                                }
-                            }
-                        })
-                })
-            }
+        ty::ty_uniq(_) => { // treat ~T like Box<T>
+            let krate = tcx.lang_items.owned_box().map(|d| d.krate);
+            krate == Some(ast::LOCAL_CRATE)
         }
 
         ty::ty_trait(ref tt) => {
             tt.principal_def_id().krate == ast::LOCAL_CRATE
         }
 
-        // Type parameters may be bound to types that are not local to
-        // the crate.
-        ty::ty_param(..) => {
-            false
-        }
-
-        // Associated types could be anything, I guess.
-        ty::ty_projection(..) => {
-            false
-        }
-
+        ty::ty_unboxed_closure(..) |
         ty::ty_infer(..) |
         ty::ty_open(..) |
         ty::ty_err => {
@@ -165,3 +152,27 @@ pub fn ty_is_local<'tcx>(tcx: &ty::ctxt<'tcx>, ty: Ty<'tcx>) -> bool {
         }
     }
 }
+
+fn type_parameters_covered_by_ty<'tcx>(tcx: &ty::ctxt<'tcx>,
+                                 ty: Ty<'tcx>)
+                                 -> HashSet<ty::ParamTy>
+{
+    if ty_is_local_constructor(tcx, ty) {
+        type_parameters_reachable_from_ty(ty)
+    } else {
+        ty.walk_children().flat_map(|t| type_parameters_covered_by_ty(tcx, t).into_iter()).collect()
+    }
+}
+
+/// All type parameters reachable from `ty`
+fn type_parameters_reachable_from_ty<'tcx>(ty: Ty<'tcx>) -> HashSet<ty::ParamTy> {
+    ty.walk()
+        .filter_map(|t| {
+            match t.sty {
+                ty::ty_param(ref param_ty) => Some(param_ty.clone()),
+                _ => None,
+            }
+        })
+        .collect()
+}
+
diff --git a/src/librustc/middle/traits/mod.rs b/src/librustc/middle/traits/mod.rs
index b10dfa5b718..fc2eb43c8a5 100644
--- a/src/librustc/middle/traits/mod.rs
+++ b/src/librustc/middle/traits/mod.rs
@@ -25,6 +25,8 @@ use syntax::codemap::{Span, DUMMY_SP};
 use util::ppaux::Repr;
 
 pub use self::error_reporting::report_fulfillment_errors;
+pub use self::coherence::orphan_check;
+pub use self::coherence::OrphanCheckErr;
 pub use self::fulfill::{FulfillmentContext, RegionObligation};
 pub use self::project::MismatchedProjectionTypes;
 pub use self::project::normalize;
@@ -245,15 +247,6 @@ pub struct VtableBuiltinData<N> {
     pub nested: subst::VecPerParamSpace<N>
 }
 
-/// True if neither the trait nor self type is local. Note that `impl_def_id` must refer to an impl
-/// of a trait, not an inherent impl.
-pub fn is_orphan_impl(tcx: &ty::ctxt,
-                      impl_def_id: ast::DefId)
-                      -> bool
-{
-    !coherence::impl_is_local(tcx, impl_def_id)
-}
-
 /// True if there exist types that satisfy both of the two given impls.
 pub fn overlapping_impls(infcx: &InferCtxt,
                          impl1_def_id: ast::DefId,
diff --git a/src/librustc_back/lib.rs b/src/librustc_back/lib.rs
index cb547df7d9c..2bb99a7141f 100644
--- a/src/librustc_back/lib.rs
+++ b/src/librustc_back/lib.rs
@@ -32,6 +32,7 @@
 #![allow(unknown_features)]
 #![feature(globs, phase, macro_rules, slicing_syntax)]
 #![feature(unboxed_closures)]
+#![feature(old_orphan_check)]
 
 #[phase(plugin, link)]
 extern crate log;
diff --git a/src/librustc_borrowck/lib.rs b/src/librustc_borrowck/lib.rs
index 664d470b11b..b886883c73a 100644
--- a/src/librustc_borrowck/lib.rs
+++ b/src/librustc_borrowck/lib.rs
@@ -16,10 +16,12 @@
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/")]
 
+#![allow(unknown_features)]
 #![feature(default_type_params, globs, macro_rules, phase, quote)]
 #![feature(slicing_syntax, unsafe_destructor)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(unboxed_closures)]
+#![feature(old_orphan_check)]
 #![allow(non_camel_case_types)]
 
 #[phase(plugin, link)] extern crate log;
diff --git a/src/librustc_trans/lib.rs b/src/librustc_trans/lib.rs
index 784002287b7..5ffe9b2d647 100644
--- a/src/librustc_trans/lib.rs
+++ b/src/librustc_trans/lib.rs
@@ -22,10 +22,12 @@
       html_favicon_url = "http://www.rust-lang.org/favicon.ico",
       html_root_url = "http://doc.rust-lang.org/nightly/")]
 
+#![allow(unknown_features)]
 #![feature(default_type_params, globs, macro_rules, phase, quote)]
 #![feature(slicing_syntax, unsafe_destructor)]
 #![feature(rustc_diagnostic_macros)]
 #![feature(unboxed_closures)]
+#![feature(old_orphan_check)]
 
 extern crate arena;
 extern crate flate;
diff --git a/src/librustc_typeck/coherence/orphan.rs b/src/librustc_typeck/coherence/orphan.rs
index 79443200ddf..44b27ec2e12 100644
--- a/src/librustc_typeck/coherence/orphan.rs
+++ b/src/librustc_typeck/coherence/orphan.rs
@@ -18,7 +18,7 @@ use syntax::ast;
 use syntax::ast_util;
 use syntax::codemap::Span;
 use syntax::visit;
-use util::ppaux::Repr;
+use util::ppaux::{Repr, UserString};
 
 pub fn check(tcx: &ty::ctxt) {
     let mut orphan = OrphanChecker { tcx: tcx };
@@ -67,10 +67,27 @@ 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));
-                if traits::is_orphan_impl(self.tcx, def_id) {
-                    span_err!(self.tcx.sess, item.span, E0117,
-                              "cannot provide an extension implementation \
-                               where both trait and type are not defined in this crate");
+                match traits::orphan_check(self.tcx, def_id) {
+                    Ok(()) => { }
+                    Err(traits::OrphanCheckErr::NoLocalInputType) => {
+                        span_err!(self.tcx.sess, item.span, E0117,
+                                  "cannot provide an extension implementation \
+                                   where both trait and type are not defined in this crate");
+                    }
+                    Err(traits::OrphanCheckErr::UncoveredTypeParameter(param_ty)) => {
+                        if !self.tcx.sess.features.borrow().old_orphan_check {
+                            self.tcx.sess.span_err(
+                                item.span,
+                                format!("type parameter `{}` must also appear as a type parameter \
+                                         of some type defined within this crate",
+                                        param_ty.user_string(self.tcx)).as_slice());
+                            self.tcx.sess.span_note(
+                                item.span,
+                                format!("for a limited time, you can add \
+                                         `#![feature(old_orphan_check)]` to your crate \
+                                         to disable this rule").as_slice());
+                        }
+                    }
                 }
             }
             _ => {
diff --git a/src/librustdoc/lib.rs b/src/librustdoc/lib.rs
index ccdc8164255..e1d9ebd7aa2 100644
--- a/src/librustdoc/lib.rs
+++ b/src/librustdoc/lib.rs
@@ -20,6 +20,7 @@
 #![allow(unknown_features)]
 #![feature(globs, macro_rules, phase, slicing_syntax)]
 #![feature(unboxed_closures)]
+#![feature(old_orphan_check)]
 
 extern crate arena;
 extern crate getopts;
diff --git a/src/libserialize/json.rs b/src/libserialize/json.rs
index 3f0d59c319a..684856ae33b 100644
--- a/src/libserialize/json.rs
+++ b/src/libserialize/json.rs
@@ -81,7 +81,7 @@
 //! use serialize::json;
 //!
 //! // Automatically generate `Decodable` and `Encodable` trait implementations
-//! #[deriving(Decodable, Encodable)]
+//! #[deriving(RustcDecodable, RustcEncodable)]
 //! pub struct TestStruct  {
 //!     data_int: u8,
 //!     data_str: String,
diff --git a/src/libstd/lib.rs b/src/libstd/lib.rs
index 74c387c5eea..9e8fba21df5 100644
--- a/src/libstd/lib.rs
+++ b/src/libstd/lib.rs
@@ -107,6 +107,7 @@
 #![feature(macro_rules, globs, linkage, thread_local, asm)]
 #![feature(default_type_params, phase, lang_items, unsafe_destructor)]
 #![feature(slicing_syntax, unboxed_closures)]
+#![feature(old_orphan_check)]
 
 // Don't link to std. We are std.
 #![no_std]
diff --git a/src/libsyntax/feature_gate.rs b/src/libsyntax/feature_gate.rs
index b2c2d7eb626..23c4ee8f64b 100644
--- a/src/libsyntax/feature_gate.rs
+++ b/src/libsyntax/feature_gate.rs
@@ -77,8 +77,11 @@ static KNOWN_FEATURES: &'static [(&'static str, Status)] = &[
     // to bootstrap fix for #5723.
     ("issue_5723_bootstrap", Accepted),
 
-    // A way to temporary opt out of opt in copy. This will *never* be accepted.
-    ("opt_out_copy", Active),
+    // A way to temporarily opt out of opt in copy. This will *never* be accepted.
+    ("opt_out_copy", Deprecated),
+
+    // A way to temporarily opt out of the new orphan rules. This will *never* be accepted.
+    ("old_orphan_check", Deprecated),
 
     // These are used to test this portion of the compiler, they don't actually
     // mean anything
@@ -91,6 +94,10 @@ enum Status {
     /// currently being considered for addition/removal.
     Active,
 
+    /// Represents a feature gate that is temporarily enabling deprecated behavior.
+    /// This gate will never be accepted.
+    Deprecated,
+
     /// Represents a feature which has since been removed (it was once Active)
     Removed,
 
@@ -108,6 +115,7 @@ pub struct Features {
     pub visible_private_types: bool,
     pub quote: bool,
     pub opt_out_copy: bool,
+    pub old_orphan_check: bool,
 }
 
 impl Features {
@@ -120,6 +128,7 @@ impl Features {
             visible_private_types: false,
             quote: false,
             opt_out_copy: false,
+            old_orphan_check: false,
         }
     }
 }
@@ -442,7 +451,16 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
                     };
                     match KNOWN_FEATURES.iter()
                                         .find(|& &(n, _)| name == n) {
-                        Some(&(name, Active)) => { cx.features.push(name); }
+                        Some(&(name, Active)) => {
+                            cx.features.push(name);
+                        }
+                        Some(&(name, Deprecated)) => {
+                            cx.features.push(name);
+                            span_handler.span_warn(
+                                mi.span,
+                                "feature is deprecated and will only be available \
+                                 for a limited time, please rewrite code that relies on it");
+                        }
                         Some(&(_, Removed)) => {
                             span_handler.span_err(mi.span, "feature has been removed");
                         }
@@ -469,6 +487,7 @@ fn check_crate_inner<F>(cm: &CodeMap, span_handler: &SpanHandler, krate: &ast::C
         visible_private_types: cx.has_feature("visible_private_types"),
         quote: cx.has_feature("quote"),
         opt_out_copy: cx.has_feature("opt_out_copy"),
+        old_orphan_check: cx.has_feature("old_orphan_check"),
     },
     unknown_features)
 }
diff --git a/src/libsyntax/lib.rs b/src/libsyntax/lib.rs
index d5093c5055c..7a6824ac27c 100644
--- a/src/libsyntax/lib.rs
+++ b/src/libsyntax/lib.rs
@@ -26,6 +26,7 @@
 #![feature(macro_rules, globs, default_type_params, phase, slicing_syntax)]
 #![feature(quote, unsafe_destructor)]
 #![feature(unboxed_closures)]
+#![feature(old_orphan_check)]
 
 extern crate arena;
 extern crate fmt_macros;
diff --git a/src/libtest/lib.rs b/src/libtest/lib.rs
index c097e933790..e61de01e0ac 100644
--- a/src/libtest/lib.rs
+++ b/src/libtest/lib.rs
@@ -31,8 +31,10 @@
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/nightly/")]
 
+#![allow(unknown_features)]
 #![feature(asm, macro_rules, phase, globs, slicing_syntax)]
 #![feature(unboxed_closures, default_type_params)]
+#![feature(old_orphan_check)]
 
 extern crate getopts;
 extern crate regex;
diff --git a/src/libtime/lib.rs b/src/libtime/lib.rs
index 87a00334c47..b5976c46a7d 100644
--- a/src/libtime/lib.rs
+++ b/src/libtime/lib.rs
@@ -20,7 +20,10 @@
        html_favicon_url = "http://www.rust-lang.org/favicon.ico",
        html_root_url = "http://doc.rust-lang.org/nightly/",
        html_playground_url = "http://play.rust-lang.org/")]
+
+#![allow(unknown_features)]
 #![feature(phase, globs)]
+#![feature(old_orphan_check)]
 
 #[cfg(test)] #[phase(plugin, link)] extern crate log;
 
diff --git a/src/test/compile-fail/opt-out-copy-bad.rs b/src/test/compile-fail/opt-out-copy-bad.rs
index 80f8a154d58..4aae8fa87da 100644
--- a/src/test/compile-fail/opt-out-copy-bad.rs
+++ b/src/test/compile-fail/opt-out-copy-bad.rs
@@ -9,6 +9,8 @@
 // except according to those terms.
 
 #![feature(opt_out_copy)]
+//~^ WARNING feature is deprecated
+//~| WARNING feature is deprecated
 
 // Test that when using the `opt-out-copy` feature we still consider
 // destructors to be non-movable
diff --git a/src/test/run-pass/deriving-encodable-decodable-box.rs b/src/test/run-pass/deriving-encodable-decodable-box.rs
index e21f64cd74c..a24ae22b224 100644
--- a/src/test/run-pass/deriving-encodable-decodable-box.rs
+++ b/src/test/run-pass/deriving-encodable-decodable-box.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(old_orphan_check)]
+
 extern crate serialize;
 
 use serialize::{Encodable, Decodable};
diff --git a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs b/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs
index a846f852694..f5df1940fa4 100644
--- a/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs
+++ b/src/test/run-pass/deriving-encodable-decodable-cell-refcell.rs
@@ -11,6 +11,8 @@
 // This briefly tests the capability of `Cell` and `RefCell` to implement the
 // `Encodable` and `Decodable` traits via `#[deriving(Encodable, Decodable)]`
 
+#![feature(old_orphan_check)]
+
 extern crate serialize;
 
 use std::cell::{Cell, RefCell};
diff --git a/src/test/run-pass/deriving-global.rs b/src/test/run-pass/deriving-global.rs
index 2322675661c..9ece4af278b 100644
--- a/src/test/run-pass/deriving-global.rs
+++ b/src/test/run-pass/deriving-global.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(old_orphan_check)]
+
 extern crate serialize;
 extern crate rand;
 
diff --git a/src/test/run-pass/issue-11881.rs b/src/test/run-pass/issue-11881.rs
index 8de847bfa33..10370ba22c8 100644
--- a/src/test/run-pass/issue-11881.rs
+++ b/src/test/run-pass/issue-11881.rs
@@ -8,6 +8,8 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(old_orphan_check)]
+
 extern crate rbml;
 extern crate serialize;
 
diff --git a/src/test/run-pass/issue-14021.rs b/src/test/run-pass/issue-14021.rs
index a55cded87e5..39b4a726d45 100644
--- a/src/test/run-pass/issue-14021.rs
+++ b/src/test/run-pass/issue-14021.rs
@@ -8,6 +8,7 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+#![feature(old_orphan_check)]
 
 extern crate serialize;
 
diff --git a/src/test/run-pass/issue-15734.rs b/src/test/run-pass/issue-15734.rs
index ea5bd550d53..72123b8e5a5 100644
--- a/src/test/run-pass/issue-15734.rs
+++ b/src/test/run-pass/issue-15734.rs
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// If `Index` used an associated type for its output, this test would
+// work more smoothly.
+#![feature(old_orphan_check)]
+
 struct Mat<T> { data: Vec<T>, cols: uint, }
 
 impl<T> Mat<T> {
diff --git a/src/test/run-pass/issue-3743.rs b/src/test/run-pass/issue-3743.rs
index 80d3d29bc00..ac200c81143 100644
--- a/src/test/run-pass/issue-3743.rs
+++ b/src/test/run-pass/issue-3743.rs
@@ -8,6 +8,10 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// If `Mul` used an associated type for its output, this test would
+// work more smoothly.
+#![feature(old_orphan_check)]
+
 struct Vec2 {
     x: f64,
     y: f64
diff --git a/src/test/run-pass/overloaded-calls-param-vtables.rs b/src/test/run-pass/overloaded-calls-param-vtables.rs
index 2e8ec3916bd..96420f17deb 100644
--- a/src/test/run-pass/overloaded-calls-param-vtables.rs
+++ b/src/test/run-pass/overloaded-calls-param-vtables.rs
@@ -14,9 +14,9 @@
 
 use std::ops::Fn;
 
-struct G;
+struct G<A>;
 
-impl<'a, A: Add<int, int>> Fn<(A,), int> for G {
+impl<'a, A: Add<int, int>> Fn<(A,), int> for G<A> {
     extern "rust-call" fn call(&self, (arg,): (A,)) -> int {
         arg.add(1)
     }