about summary refs log tree commit diff
diff options
context:
space:
mode:
authorbors <bors@rust-lang.org>2016-05-06 06:21:25 -0700
committerbors <bors@rust-lang.org>2016-05-06 06:21:25 -0700
commit5158f3b282287624232ac6935569e440bb182664 (patch)
tree8a0d041a345b5f548b3b1b7ebbfb9459abddf311
parenta36c41912ba91435d75ab5702ed8bc30116565fe (diff)
parent238e4ee104179c5a6beb5bb25ffe28a3fd77bff5 (diff)
downloadrust-5158f3b282287624232ac6935569e440bb182664.tar.gz
rust-5158f3b282287624232ac6935569e440bb182664.zip
Auto merge of #33138 - arielb1:sized-shortcut, r=nikomatsakis
Short-cut `T: Sized` trait selection for ADTs

Basically avoids all nested obligations when checking whether an ADT is sized - this speeds up typeck by ~15%

The refactoring fixed #32963, but I also want to make `Copy` not object-safe (will commit that soon).

Fixes #33201

r? @nikomatsakis
-rw-r--r--src/libcore/num/bignum.rs2
-rw-r--r--src/librustc/dep_graph/dep_node.rs2
-rw-r--r--src/librustc/infer/mod.rs11
-rw-r--r--src/librustc/lint/builtin.rs16
-rw-r--r--src/librustc/middle/free_region.rs1
-rw-r--r--src/librustc/traits/error_reporting.rs156
-rw-r--r--src/librustc/traits/fulfill.rs54
-rw-r--r--src/librustc/traits/mod.rs6
-rw-r--r--src/librustc/traits/object_safety.rs2
-rw-r--r--src/librustc/traits/select.rs481
-rw-r--r--src/librustc/traits/util.rs63
-rw-r--r--src/librustc/ty/fold.rs3
-rw-r--r--src/librustc/ty/mod.rs192
-rw-r--r--src/librustc/ty/structural_impls.rs3
-rw-r--r--src/librustc/ty/util.rs1
-rw-r--r--src/librustc/ty/wf.rs70
-rw-r--r--src/librustc/util/ppaux.rs6
-rw-r--r--src/librustc_back/sha2.rs2
-rw-r--r--src/librustc_lint/lib.rs8
-rw-r--r--src/librustc_metadata/tyencode.rs3
-rw-r--r--src/librustc_passes/consts.rs3
-rw-r--r--src/librustc_typeck/astconv.rs4
-rw-r--r--src/librustc_typeck/check/closure.rs1
-rw-r--r--src/librustc_typeck/check/coercion.rs2
-rw-r--r--src/librustc_typeck/check/dropck.rs5
-rw-r--r--src/librustc_typeck/check/method/probe.rs1
-rw-r--r--src/librustc_typeck/check/mod.rs9
-rw-r--r--src/librustc_typeck/collect.rs1
-rw-r--r--src/librustdoc/clean/mod.rs1
-rw-r--r--src/test/compile-fail/issue-17431-2.rs1
-rw-r--r--src/test/compile-fail/issue-20692.rs1
-rw-r--r--src/test/compile-fail/issue-26548.rs3
-rw-r--r--src/test/compile-fail/issue-32963.rs20
-rw-r--r--src/test/compile-fail/kindck-copy.rs8
-rw-r--r--src/test/compile-fail/range-1.rs1
-rw-r--r--src/test/compile-fail/rfc1592-deprecated.rs32
-rw-r--r--src/test/compile-fail/sized-cycle-note.rs7
-rw-r--r--src/test/compile-fail/unsized6.rs4
-rw-r--r--src/test/run-pass/issue-31299.rs43
-rw-r--r--src/test/run-pass/rfc1592-deprecated.rs29
40 files changed, 845 insertions, 413 deletions
diff --git a/src/libcore/num/bignum.rs b/src/libcore/num/bignum.rs
index 66c6deb3615..a881b539ced 100644
--- a/src/libcore/num/bignum.rs
+++ b/src/libcore/num/bignum.rs
@@ -33,7 +33,7 @@ use mem;
 use intrinsics;
 
 /// Arithmetic operations required by bignums.
-pub trait FullOps {
+pub trait FullOps: Sized {
     /// Returns `(carry', v')` such that `carry' * 2^W + v' = self + other + carry`,
     /// where `W` is the number of bits in `Self`.
     fn full_add(self, other: Self, carry: bool) -> (bool /*carry*/, Self);
diff --git a/src/librustc/dep_graph/dep_node.rs b/src/librustc/dep_graph/dep_node.rs
index 536c739bf16..85b4b4f59c4 100644
--- a/src/librustc/dep_graph/dep_node.rs
+++ b/src/librustc/dep_graph/dep_node.rs
@@ -88,6 +88,7 @@ pub enum DepNode<D: Clone + Debug> {
     ImplOrTraitItems(D),
     ItemSignature(D),
     FieldTy(D),
+    SizedConstraint(D),
     TraitItemDefIds(D),
     InherentImpls(D),
     ImplItems(D),
@@ -193,6 +194,7 @@ impl<D: Clone + Debug> DepNode<D> {
             ImplOrTraitItems(ref d) => op(d).map(ImplOrTraitItems),
             ItemSignature(ref d) => op(d).map(ItemSignature),
             FieldTy(ref d) => op(d).map(FieldTy),
+            SizedConstraint(ref d) => op(d).map(SizedConstraint),
             TraitItemDefIds(ref d) => op(d).map(TraitItemDefIds),
             InherentImpls(ref d) => op(d).map(InherentImpls),
             ImplItems(ref d) => op(d).map(ImplItems),
diff --git a/src/librustc/infer/mod.rs b/src/librustc/infer/mod.rs
index 312a446d440..6da4c44fe9a 100644
--- a/src/librustc/infer/mod.rs
+++ b/src/librustc/infer/mod.rs
@@ -814,6 +814,17 @@ impl<'a, 'tcx> InferCtxt<'a, 'tcx> {
         r
     }
 
+    // Execute `f` in a snapshot, and commit the bindings it creates
+    pub fn in_snapshot<T, F>(&self, f: F) -> T where
+        F: FnOnce(&CombinedSnapshot) -> T
+    {
+        debug!("in_snapshot()");
+        let snapshot = self.start_snapshot();
+        let r = f(&snapshot);
+        self.commit_from(snapshot);
+        r
+    }
+
     /// Execute `f` and commit only the region bindings if successful.
     /// The function f must be very careful not to leak any non-region
     /// variables that get created.
diff --git a/src/librustc/lint/builtin.rs b/src/librustc/lint/builtin.rs
index 2564838c67d..6dd98425df3 100644
--- a/src/librustc/lint/builtin.rs
+++ b/src/librustc/lint/builtin.rs
@@ -185,6 +185,18 @@ declare_lint! {
     "detects super or self keywords at the beginning of global path"
 }
 
+declare_lint! {
+    pub UNSIZED_IN_TUPLE,
+    Warn,
+    "unsized types in the interior of a tuple were erroneously allowed"
+}
+
+declare_lint! {
+    pub OBJECT_UNSAFE_FRAGMENT,
+    Warn,
+    "object-unsafe non-principal fragments in object types were erroneously allowed"
+}
+
 /// Does nothing as a lint pass, but registers some `Lint`s
 /// which are used by other parts of the compiler.
 #[derive(Copy, Clone)]
@@ -220,7 +232,9 @@ impl LintPass for HardwiredLints {
             TRANSMUTE_FROM_FN_ITEM_TYPES,
             OVERLAPPING_INHERENT_IMPLS,
             RENAMED_AND_REMOVED_LINTS,
-            SUPER_OR_SELF_IN_GLOBAL_PATH
+            SUPER_OR_SELF_IN_GLOBAL_PATH,
+            UNSIZED_IN_TUPLE,
+            OBJECT_UNSAFE_FRAGMENT
         )
     }
 }
diff --git a/src/librustc/middle/free_region.rs b/src/librustc/middle/free_region.rs
index 51eebd43731..758fb7a81fd 100644
--- a/src/librustc/middle/free_region.rs
+++ b/src/librustc/middle/free_region.rs
@@ -56,6 +56,7 @@ impl FreeRegionMap {
             match *predicate {
                 ty::Predicate::Projection(..) |
                 ty::Predicate::Trait(..) |
+                ty::Predicate::Rfc1592(..) |
                 ty::Predicate::Equate(..) |
                 ty::Predicate::WellFormed(..) |
                 ty::Predicate::ObjectSafe(..) |
diff --git a/src/librustc/traits/error_reporting.rs b/src/librustc/traits/error_reporting.rs
index 531a4fbf8be..b89ce2ce3b2 100644
--- a/src/librustc/traits/error_reporting.rs
+++ b/src/librustc/traits/error_reporting.rs
@@ -36,23 +36,27 @@ use util::nodemap::{FnvHashMap, FnvHashSet};
 use std::cmp;
 use std::fmt;
 use syntax::attr::{AttributeMethods, AttrMetaMethods};
+use syntax::ast;
 use syntax::codemap::Span;
 use syntax::errors::DiagnosticBuilder;
 
 #[derive(Debug, PartialEq, Eq, Hash)]
 pub struct TraitErrorKey<'tcx> {
     span: Span,
+    warning_node_id: Option<ast::NodeId>,
     predicate: ty::Predicate<'tcx>
 }
 
 impl<'tcx> TraitErrorKey<'tcx> {
     fn from_error<'a>(infcx: &InferCtxt<'a, 'tcx>,
-                      e: &FulfillmentError<'tcx>) -> Self {
+                      e: &FulfillmentError<'tcx>,
+                      warning_node_id: Option<ast::NodeId>) -> Self {
         let predicate =
             infcx.resolve_type_vars_if_possible(&e.obligation.predicate);
         TraitErrorKey {
             span: e.obligation.cause.span,
-            predicate: infcx.tcx.erase_regions(&predicate)
+            predicate: infcx.tcx.erase_regions(&predicate),
+            warning_node_id: warning_node_id
         }
     }
 }
@@ -60,13 +64,23 @@ impl<'tcx> TraitErrorKey<'tcx> {
 pub fn report_fulfillment_errors<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                            errors: &Vec<FulfillmentError<'tcx>>) {
     for error in errors {
-        report_fulfillment_error(infcx, error);
+        report_fulfillment_error(infcx, error, None);
+    }
+}
+
+pub fn report_fulfillment_errors_as_warnings<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
+                                                       errors: &Vec<FulfillmentError<'tcx>>,
+                                                       node_id: ast::NodeId)
+{
+    for error in errors {
+        report_fulfillment_error(infcx, error, Some(node_id));
     }
 }
 
 fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
-                                      error: &FulfillmentError<'tcx>) {
-    let error_key = TraitErrorKey::from_error(infcx, error);
+                                      error: &FulfillmentError<'tcx>,
+                                      warning_node_id: Option<ast::NodeId>) {
+    let error_key = TraitErrorKey::from_error(infcx, error, warning_node_id);
     debug!("report_fulfillment_errors({:?}) - key={:?}",
            error, error_key);
     if !infcx.reported_trait_errors.borrow_mut().insert(error_key) {
@@ -75,10 +89,10 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
     }
     match error.code {
         FulfillmentErrorCode::CodeSelectionError(ref e) => {
-            report_selection_error(infcx, &error.obligation, e);
+            report_selection_error(infcx, &error.obligation, e, warning_node_id);
         }
         FulfillmentErrorCode::CodeProjectionError(ref e) => {
-            report_projection_error(infcx, &error.obligation, e);
+            report_projection_error(infcx, &error.obligation, e, warning_node_id);
         }
         FulfillmentErrorCode::CodeAmbiguity => {
             maybe_report_ambiguity(infcx, &error.obligation);
@@ -88,18 +102,29 @@ fn report_fulfillment_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 
 pub fn report_projection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                          obligation: &PredicateObligation<'tcx>,
-                                         error: &MismatchedProjectionTypes<'tcx>)
+                                         error: &MismatchedProjectionTypes<'tcx>,
+                                         warning_node_id: Option<ast::NodeId>)
 {
     let predicate =
         infcx.resolve_type_vars_if_possible(&obligation.predicate);
 
     if !predicate.references_error() {
-        let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
-            "type mismatch resolving `{}`: {}",
-            predicate,
-            error.err);
-        note_obligation_cause(infcx, &mut err, obligation);
-        err.emit();
+        if let Some(warning_node_id) = warning_node_id {
+            infcx.tcx.sess.add_lint(
+                ::lint::builtin::UNSIZED_IN_TUPLE,
+                warning_node_id,
+                obligation.cause.span,
+                format!("type mismatch resolving `{}`: {}",
+                        predicate,
+                        error.err));
+        } else {
+            let mut err = struct_span_err!(infcx.tcx.sess, obligation.cause.span, E0271,
+                                           "type mismatch resolving `{}`: {}",
+                                           predicate,
+                                           error.err);
+            note_obligation_cause(infcx, &mut err, obligation);
+            err.emit();
+        }
     }
 }
 
@@ -383,7 +408,8 @@ pub fn recursive_type_with_infinite_size_error<'tcx>(tcx: &TyCtxt<'tcx>,
 
 pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                                         obligation: &PredicateObligation<'tcx>,
-                                        error: &SelectionError<'tcx>)
+                                        error: &SelectionError<'tcx>,
+                                        warning_node_id: Option<ast::NodeId>)
 {
     match *error {
         SelectionError::Unimplemented => {
@@ -401,6 +427,17 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 
                         if !infcx.tcx.sess.has_errors() || !trait_predicate.references_error() {
                             let trait_ref = trait_predicate.to_poly_trait_ref();
+
+                            if let Some(warning_node_id) = warning_node_id {
+                                infcx.tcx.sess.add_lint(
+                                    ::lint::builtin::UNSIZED_IN_TUPLE,
+                                    warning_node_id,
+                                    obligation.cause.span,
+                                    format!("the trait bound `{}` is not satisfied",
+                                            trait_ref.to_predicate()));
+                                return;
+                            }
+
                             let mut err = struct_span_err!(
                                 infcx.tcx.sess, obligation.cause.span, E0277,
                                 "the trait bound `{}` is not satisfied",
@@ -480,12 +517,15 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                     ty::Predicate::ObjectSafe(trait_def_id) => {
                         let violations = object_safety_violations(
                             infcx.tcx, trait_def_id);
-                        let mut err = report_object_safety_error(infcx.tcx,
-                                                                 obligation.cause.span,
-                                                                 trait_def_id,
-                                                                 violations);
-                        note_obligation_cause(infcx, &mut err, obligation);
-                        err.emit();
+                        let err = report_object_safety_error(infcx.tcx,
+                                                             obligation.cause.span,
+                                                             trait_def_id,
+                                                             warning_node_id,
+                                                             violations);
+                        if let Some(mut err) = err {
+                            note_obligation_cause(infcx, &mut err, obligation);
+                            err.emit();
+                        }
                     }
 
                     ty::Predicate::ClosureKind(closure_def_id, kind) => {
@@ -514,6 +554,13 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
                             "WF predicate not satisfied for {:?}",
                             ty);
                     }
+
+                    ty::Predicate::Rfc1592(ref data) => {
+                        span_bug!(
+                            obligation.cause.span,
+                            "RFC1592 predicate not satisfied for {:?}",
+                            data);
+                    }
                 }
             }
         }
@@ -537,10 +584,13 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 
         TraitNotObjectSafe(did) => {
             let violations = object_safety_violations(infcx.tcx, did);
-            let mut err = report_object_safety_error(infcx.tcx, obligation.cause.span, did,
-                                                     violations);
-            note_obligation_cause(infcx, &mut err, obligation);
-            err.emit();
+            let err = report_object_safety_error(infcx.tcx, obligation.cause.span, did,
+                                                 warning_node_id,
+                                                 violations);
+            if let Some(mut err) = err {
+                note_obligation_cause(infcx, &mut err, obligation);
+                err.emit();
+            }
         }
     }
 }
@@ -548,47 +598,70 @@ pub fn report_selection_error<'a, 'tcx>(infcx: &InferCtxt<'a, 'tcx>,
 pub fn report_object_safety_error<'tcx>(tcx: &TyCtxt<'tcx>,
                                         span: Span,
                                         trait_def_id: DefId,
+                                        warning_node_id: Option<ast::NodeId>,
                                         violations: Vec<ObjectSafetyViolation>)
-                                        -> DiagnosticBuilder<'tcx>
+                                        -> Option<DiagnosticBuilder<'tcx>>
 {
-    let mut err = struct_span_err!(
-        tcx.sess, span, E0038,
-        "the trait `{}` cannot be made into an object",
-        tcx.item_path_str(trait_def_id));
+    let mut err = match warning_node_id {
+        Some(_) => None,
+        None => {
+            Some(struct_span_err!(
+                tcx.sess, span, E0038,
+                "the trait `{}` cannot be made into an object",
+                tcx.item_path_str(trait_def_id)))
+        }
+    };
 
     let mut reported_violations = FnvHashSet();
     for violation in violations {
         if !reported_violations.insert(violation.clone()) {
             continue;
         }
-        match violation {
+        let buf;
+        let note = match violation {
             ObjectSafetyViolation::SizedSelf => {
-                err.note("the trait cannot require that `Self : Sized`");
+                "the trait cannot require that `Self : Sized`"
             }
 
             ObjectSafetyViolation::SupertraitSelf => {
-                err.note("the trait cannot use `Self` as a type parameter \
-                          in the supertrait listing");
+                "the trait cannot use `Self` as a type parameter \
+                     in the supertrait listing"
             }
 
             ObjectSafetyViolation::Method(method,
                                           MethodViolationCode::StaticMethod) => {
-                err.note(&format!("method `{}` has no receiver",
-                         method.name));
+                buf = format!("method `{}` has no receiver",
+                              method.name);
+                &buf
             }
 
             ObjectSafetyViolation::Method(method,
                                           MethodViolationCode::ReferencesSelf) => {
-                err.note(&format!("method `{}` references the `Self` type \
+                buf = format!("method `{}` references the `Self` type \
                                    in its arguments or return type",
-                                  method.name));
+                              method.name);
+                &buf
             }
 
             ObjectSafetyViolation::Method(method,
                                           MethodViolationCode::Generic) => {
-                err.note(&format!("method `{}` has generic type parameters",
-                                  method.name));
+                buf = format!("method `{}` has generic type parameters",
+                              method.name);
+                &buf
             }
+        };
+        match (warning_node_id, &mut err) {
+            (Some(node_id), &mut None) => {
+                tcx.sess.add_lint(
+                    ::lint::builtin::OBJECT_UNSAFE_FRAGMENT,
+                    node_id,
+                    span,
+                    note.to_string());
+            }
+            (None, &mut Some(ref mut err)) => {
+                err.note(note);
+            }
+            _ => unreachable!()
         }
     }
     err
@@ -764,6 +837,9 @@ fn note_obligation_cause_code<'a, 'tcx, T>(infcx: &InferCtxt<'a, 'tcx>,
         ObligationCauseCode::SliceOrArrayElem => {
             err.note("slice and array elements must have `Sized` type");
         }
+        ObligationCauseCode::TupleElem => {
+            err.note("tuple elements must have `Sized` type");
+        }
         ObligationCauseCode::ProjectionWf(data) => {
             err.note(&format!("required so that the projection `{}` is well-formed",
                               data));
diff --git a/src/librustc/traits/fulfill.rs b/src/librustc/traits/fulfill.rs
index 8946ec2153b..a184e951b83 100644
--- a/src/librustc/traits/fulfill.rs
+++ b/src/librustc/traits/fulfill.rs
@@ -13,6 +13,7 @@ use infer::{InferCtxt, InferOk};
 use ty::{self, Ty, TyCtxt, TypeFoldable, ToPolyTraitRef};
 use rustc_data_structures::obligation_forest::{Backtrace, ObligationForest, Error};
 use std::iter;
+use std::mem;
 use syntax::ast;
 use util::common::ErrorReported;
 use util::nodemap::{FnvHashMap, FnvHashSet, NodeMap};
@@ -70,6 +71,9 @@ pub struct FulfillmentContext<'tcx> {
     predicates: ObligationForest<PendingPredicateObligation<'tcx>,
                                  LocalFulfilledPredicates<'tcx>>,
 
+    // A list of new obligations due to RFC1592.
+    rfc1592_obligations: Vec<PredicateObligation<'tcx>>,
+
     // A set of constraints that regionck must validate. Each
     // constraint has the form `T:'a`, meaning "some type `T` must
     // outlive the lifetime 'a". These constraints derive from
@@ -116,6 +120,7 @@ impl<'tcx> FulfillmentContext<'tcx> {
         FulfillmentContext {
             duplicate_set: LocalFulfilledPredicates::new(),
             predicates: ObligationForest::new(),
+            rfc1592_obligations: Vec::new(),
             region_obligations: NodeMap(),
         }
     }
@@ -197,6 +202,13 @@ impl<'tcx> FulfillmentContext<'tcx> {
         self.predicates.push_tree(obligation, LocalFulfilledPredicates::new());
     }
 
+    pub fn register_rfc1592_obligation<'a>(&mut self,
+                                           _infcx: &InferCtxt<'a,'tcx>,
+                                           obligation: PredicateObligation<'tcx>)
+    {
+        self.rfc1592_obligations.push(obligation);
+    }
+
     pub fn region_obligations(&self,
                               body_id: ast::NodeId)
                               -> &[RegionObligation<'tcx>]
@@ -207,11 +219,26 @@ impl<'tcx> FulfillmentContext<'tcx> {
         }
     }
 
+    pub fn select_rfc1592_obligations<'a>(&mut self,
+                                      infcx: &InferCtxt<'a,'tcx>)
+                                      -> Result<(),Vec<FulfillmentError<'tcx>>>
+    {
+        while !self.rfc1592_obligations.is_empty() {
+            for obligation in mem::replace(&mut self.rfc1592_obligations, Vec::new()) {
+                self.register_predicate_obligation(infcx, obligation);
+            }
+
+            self.select_all_or_error(infcx)?;
+        }
+
+        Ok(())
+    }
     pub fn select_all_or_error<'a>(&mut self,
                                    infcx: &InferCtxt<'a,'tcx>)
                                    -> Result<(),Vec<FulfillmentError<'tcx>>>
     {
         self.select_where_possible(infcx)?;
+
         let errors: Vec<_> =
             self.predicates.to_errors(CodeAmbiguity)
                            .into_iter()
@@ -279,12 +306,14 @@ impl<'tcx> FulfillmentContext<'tcx> {
             // Process pending obligations.
             let outcome = {
                 let region_obligations = &mut self.region_obligations;
+                let rfc1592_obligations = &mut self.rfc1592_obligations;
                 self.predicates.process_obligations(
                     |obligation, tree, backtrace| process_predicate(selcx,
-                                                                     tree,
-                                                                     obligation,
-                                                                     backtrace,
-                                                                     region_obligations))
+                                                                    tree,
+                                                                    obligation,
+                                                                    backtrace,
+                                                                    region_obligations,
+                                                                    rfc1592_obligations))
             };
 
             debug!("select: outcome={:?}", outcome);
@@ -321,11 +350,13 @@ fn process_predicate<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
                               tree_cache: &mut LocalFulfilledPredicates<'tcx>,
                               pending_obligation: &mut PendingPredicateObligation<'tcx>,
                               backtrace: Backtrace<PendingPredicateObligation<'tcx>>,
-                              region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
+                              region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>,
+                              rfc1592_obligations: &mut Vec<PredicateObligation<'tcx>>)
                               -> Result<Option<Vec<PendingPredicateObligation<'tcx>>>,
                                         FulfillmentErrorCode<'tcx>>
 {
-    match process_predicate1(selcx, pending_obligation, region_obligations) {
+    match process_predicate1(selcx, pending_obligation, region_obligations,
+                             rfc1592_obligations) {
         Ok(Some(v)) => process_child_obligations(selcx,
                                                  tree_cache,
                                                  &pending_obligation.obligation,
@@ -507,7 +538,8 @@ fn trait_ref_type_vars<'a, 'tcx>(selcx: &mut SelectionContext<'a, 'tcx>,
 /// - `Err` if the predicate does not hold
 fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
                                pending_obligation: &mut PendingPredicateObligation<'tcx>,
-                               region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>)
+                               region_obligations: &mut NodeMap<Vec<RegionObligation<'tcx>>>,
+                               rfc1592_obligations: &mut Vec<PredicateObligation<'tcx>>)
                                -> Result<Option<Vec<PredicateObligation<'tcx>>>,
                                          FulfillmentErrorCode<'tcx>>
 {
@@ -677,6 +709,14 @@ fn process_predicate1<'a,'tcx>(selcx: &mut SelectionContext<'a,'tcx>,
                 s => Ok(s)
             }
         }
+
+        ty::Predicate::Rfc1592(ref inner) => {
+            rfc1592_obligations.push(PredicateObligation {
+                predicate: ty::Predicate::clone(inner),
+                ..obligation.clone()
+            });
+            Ok(Some(vec![]))
+        }
     }
 }
 
diff --git a/src/librustc/traits/mod.rs b/src/librustc/traits/mod.rs
index a160465e2e8..7da95b6646a 100644
--- a/src/librustc/traits/mod.rs
+++ b/src/librustc/traits/mod.rs
@@ -28,6 +28,7 @@ use syntax::codemap::{Span, DUMMY_SP};
 pub use self::error_reporting::TraitErrorKey;
 pub use self::error_reporting::recursive_type_with_infinite_size_error;
 pub use self::error_reporting::report_fulfillment_errors;
+pub use self::error_reporting::report_fulfillment_errors_as_warnings;
 pub use self::error_reporting::report_overflow_error;
 pub use self::error_reporting::report_overflow_error_cycle;
 pub use self::error_reporting::report_selection_error;
@@ -106,9 +107,12 @@ pub enum ObligationCauseCode<'tcx> {
     /// Not well classified or should be obvious from span.
     MiscObligation,
 
-    /// This is the trait reference from the given projection
+    /// A slice or array is WF only if `T: Sized`
     SliceOrArrayElem,
 
+    /// A tuple is WF only if its middle elements are Sized
+    TupleElem,
+
     /// This is the trait reference from the given projection
     ProjectionWf(ty::ProjectionTy<'tcx>),
 
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index c870d609814..59db68b1c3c 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -166,6 +166,7 @@ pub fn supertraits_reference_self<'tcx>(tcx: &TyCtxt<'tcx>,
                 ty::Predicate::TypeOutlives(..) |
                 ty::Predicate::RegionOutlives(..) |
                 ty::Predicate::ClosureKind(..) |
+                ty::Predicate::Rfc1592(..) |
                 ty::Predicate::Equate(..) => {
                     false
                 }
@@ -204,6 +205,7 @@ fn generics_require_sized_self<'tcx>(tcx: &TyCtxt<'tcx>,
                 }
                 ty::Predicate::Projection(..) |
                 ty::Predicate::Trait(..) |
+                ty::Predicate::Rfc1592(..) |
                 ty::Predicate::Equate(..) |
                 ty::Predicate::RegionOutlives(..) |
                 ty::Predicate::WellFormed(..) |
diff --git a/src/librustc/traits/select.rs b/src/librustc/traits/select.rs
index d7528fc3130..138ca7a0f35 100644
--- a/src/librustc/traits/select.rs
+++ b/src/librustc/traits/select.rs
@@ -13,7 +13,6 @@
 pub use self::MethodMatchResult::*;
 pub use self::MethodMatchedData::*;
 use self::SelectionCandidate::*;
-use self::BuiltinBoundConditions::*;
 use self::EvaluationResult::*;
 
 use super::coherence;
@@ -50,7 +49,6 @@ use std::fmt;
 use std::rc::Rc;
 use syntax::abi::Abi;
 use hir;
-use util::common::ErrorReported;
 use util::nodemap::FnvHashMap;
 
 pub struct SelectionContext<'cx, 'tcx:'cx> {
@@ -188,7 +186,7 @@ pub enum MethodMatchedData {
 /// parameter environment.
 #[derive(PartialEq,Eq,Debug,Clone)]
 enum SelectionCandidate<'tcx> {
-    BuiltinCandidate(ty::BuiltinBound),
+    BuiltinCandidate { has_nested: bool },
     ParamCandidate(ty::PolyTraitRef<'tcx>),
     ImplCandidate(DefId),
     DefaultImplCandidate(DefId),
@@ -232,10 +230,18 @@ struct EvaluatedCandidate<'tcx> {
     evaluation: EvaluationResult,
 }
 
-enum BuiltinBoundConditions<'tcx> {
-    If(ty::Binder<Vec<Ty<'tcx>>>),
-    ParameterBuiltin,
-    AmbiguousBuiltin
+/// When does the builtin impl for `T: Trait` apply?
+enum BuiltinImplConditions<'tcx> {
+    /// The impl is conditional on T1,T2,.. : Trait
+    Where(ty::Binder<Vec<Ty<'tcx>>>),
+    /// There is no built-in impl. There may be some other
+    /// candidate (a where-clause or user-defined impl).
+    None,
+    /// There is *no* impl for this, builtin or not. Ignore
+    /// all where-clauses.
+    Never,
+    /// It is unknown whether there is an impl.
+    Ambiguous
 }
 
 #[derive(Copy, Clone, Debug, PartialOrd, Ord, PartialEq, Eq)]
@@ -412,6 +418,8 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         }
 
         match obligation.predicate {
+            ty::Predicate::Rfc1592(..) => EvaluatedToOk,
+
             ty::Predicate::Trait(ref t) => {
                 assert!(!t.has_escaping_regions());
                 let obligation = obligation.with(t.clone());
@@ -993,15 +1001,14 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 self.assemble_candidates_from_impls(obligation, &mut candidates)?;
 
                 // For other types, we'll use the builtin rules.
-                self.assemble_builtin_bound_candidates(ty::BoundCopy,
-                                                       obligation,
-                                                       &mut candidates)?;
+                let copy_conditions = self.copy_conditions(obligation);
+                self.assemble_builtin_bound_candidates(copy_conditions, &mut candidates)?;
             }
-            Some(bound @ ty::BoundSized) => {
+            Some(ty::BoundSized) => {
                 // Sized is never implementable by end-users, it is
                 // always automatically computed.
-                self.assemble_builtin_bound_candidates(bound,
-                                                       obligation,
+                let sized_conditions = self.sized_conditions(obligation);
+                self.assemble_builtin_bound_candidates(sized_conditions,
                                                        &mut candidates)?;
             }
 
@@ -1394,7 +1401,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             return;
         }
 
-        self.infcx.commit_if_ok(|snapshot| {
+        self.infcx.in_snapshot(|snapshot| {
             let (self_ty, _) =
                 self.infcx().skolemize_late_bound_regions(&obligation.self_ty(), snapshot);
             let poly_trait_ref = match self_ty.sty {
@@ -1405,7 +1412,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                                 debug!("assemble_candidates_from_object_ty: matched builtin bound, \
                                         pushing candidate");
                                 candidates.vec.push(BuiltinObjectCandidate);
-                                return Ok(());
+                                return;
                             }
                         }
                         _ => {}
@@ -1416,10 +1423,10 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 ty::TyInfer(ty::TyVar(_)) => {
                     debug!("assemble_candidates_from_object_ty: ambiguous");
                     candidates.ambiguous = true; // could wind up being an object type
-                    return Ok(());
+                    return;
                 }
                 _ => {
-                    return Ok(());
+                    return;
                 }
             };
 
@@ -1447,9 +1454,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             } else if upcast_trait_refs == 1 {
                 candidates.vec.push(ObjectCandidate);
             }
-
-            Ok::<(),()>(())
-        }).unwrap();
+        })
     }
 
     /// Search for unsizing that might apply to `obligation`.
@@ -1570,7 +1575,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                 BuiltinObjectCandidate |
                 BuiltinUnsizeCandidate |
                 DefaultImplObjectCandidate(..) |
-                BuiltinCandidate(..) => {
+                BuiltinCandidate { .. } => {
                     // We have a where-clause so don't go around looking
                     // for impls.
                     true
@@ -1608,229 +1613,131 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     // those will hopefully change to library-defined traits in the
     // future.
 
+    // HACK: if this returns an error, selection exits without considering
+    // other impls.
     fn assemble_builtin_bound_candidates<'o>(&mut self,
-                                             bound: ty::BuiltinBound,
-                                             obligation: &TraitObligation<'tcx>,
+                                             conditions: BuiltinImplConditions<'tcx>,
                                              candidates: &mut SelectionCandidateSet<'tcx>)
                                              -> Result<(),SelectionError<'tcx>>
     {
-        match self.builtin_bound(bound, obligation) {
-            Ok(If(..)) => {
-                debug!("builtin_bound: bound={:?}",
-                       bound);
-                candidates.vec.push(BuiltinCandidate(bound));
+        match conditions {
+            BuiltinImplConditions::Where(nested) => {
+                debug!("builtin_bound: nested={:?}", nested);
+                candidates.vec.push(BuiltinCandidate {
+                    has_nested: nested.skip_binder().len() > 0
+                });
                 Ok(())
             }
-            Ok(ParameterBuiltin) => { Ok(()) }
-            Ok(AmbiguousBuiltin) => {
+            BuiltinImplConditions::None => { Ok(()) }
+            BuiltinImplConditions::Ambiguous => {
                 debug!("assemble_builtin_bound_candidates: ambiguous builtin");
                 Ok(candidates.ambiguous = true)
             }
-            Err(e) => { Err(e) }
+            BuiltinImplConditions::Never => { Err(Unimplemented) }
         }
     }
 
-    fn builtin_bound(&mut self,
-                     bound: ty::BuiltinBound,
-                     obligation: &TraitObligation<'tcx>)
-                     -> Result<BuiltinBoundConditions<'tcx>,SelectionError<'tcx>>
+    fn sized_conditions(&mut self, obligation: &TraitObligation<'tcx>)
+                     -> BuiltinImplConditions<'tcx>
     {
-        // Note: these tests operate on types that may contain bound
-        // regions. To be proper, we ought to skolemize here, but we
-        // forego the skolemization and defer it until the
-        // confirmation step.
+        use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
 
-        let self_ty = self.infcx.shallow_resolve(obligation.predicate.0.self_ty());
-        return match self_ty.sty {
-            ty::TyInfer(ty::IntVar(_)) |
-            ty::TyInfer(ty::FloatVar(_)) |
-            ty::TyUint(_) |
-            ty::TyInt(_) |
-            ty::TyBool |
-            ty::TyFloat(_) |
-            ty::TyFnDef(..) |
-            ty::TyFnPtr(_) |
-            ty::TyChar => {
+        // NOTE: binder moved to (*)
+        let self_ty = self.infcx.shallow_resolve(
+            obligation.predicate.skip_binder().self_ty());
+
+        match self_ty.sty {
+            ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
+            ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
+            ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyRawPtr(..) |
+            ty::TyChar | ty::TyBox(_) | ty::TyRef(..) |
+            ty::TyArray(..) | ty::TyClosure(..) |
+            ty::TyError => {
                 // safe for everything
-                ok_if(Vec::new())
+                Where(ty::Binder(Vec::new()))
             }
 
-            ty::TyBox(_) => {  // Box<T>
-                match bound {
-                    ty::BoundCopy => Err(Unimplemented),
-
-                    ty::BoundSized => ok_if(Vec::new()),
+            ty::TyStr | ty::TySlice(_) | ty::TyTrait(..) => Never,
 
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-                }
+            ty::TyTuple(ref tys) => {
+                // FIXME(#33242) we only need to constrain the last field
+                Where(ty::Binder(tys.clone()))
             }
 
-            ty::TyRawPtr(..) => {     // *const T, *mut T
-                match bound {
-                    ty::BoundCopy | ty::BoundSized => ok_if(Vec::new()),
-
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-                }
+            ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
+                let sized_crit = def.sized_constraint(self.tcx());
+                // (*) binder moved here
+                Where(ty::Binder(match sized_crit.sty {
+                    ty::TyTuple(ref tys) => tys.to_owned().subst(self.tcx(), substs),
+                    ty::TyBool => vec![],
+                    _ => vec![sized_crit.subst(self.tcx(), substs)]
+                }))
             }
 
-            ty::TyTrait(ref data) => {
-                match bound {
-                    ty::BoundSized => Err(Unimplemented),
-                    ty::BoundCopy => {
-                        if data.bounds.builtin_bounds.contains(&bound) {
-                            ok_if(Vec::new())
-                        } else {
-                            // Recursively check all supertraits to find out if any further
-                            // bounds are required and thus we must fulfill.
-                            let principal =
-                                data.principal_trait_ref_with_self_ty(self.tcx(),
-                                                                      self.tcx().types.err);
-                            let copy_def_id = obligation.predicate.def_id();
-                            for tr in util::supertraits(self.tcx(), principal) {
-                                if tr.def_id() == copy_def_id {
-                                    return ok_if(Vec::new())
-                                }
-                            }
+            ty::TyProjection(_) | ty::TyParam(_) => None,
+            ty::TyInfer(ty::TyVar(_)) => Ambiguous,
 
-                            Err(Unimplemented)
-                        }
-                    }
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-                }
+            ty::TyInfer(ty::FreshTy(_))
+            | ty::TyInfer(ty::FreshIntTy(_))
+            | ty::TyInfer(ty::FreshFloatTy(_)) => {
+                bug!("asked to assemble builtin bounds of unexpected type: {:?}",
+                     self_ty);
             }
+        }
+    }
 
-            ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl }) => {
-                // &mut T or &T
-                match bound {
-                    ty::BoundCopy => {
-                        match mutbl {
-                            // &mut T is affine and hence never `Copy`
-                            hir::MutMutable => Err(Unimplemented),
-
-                            // &T is always copyable
-                            hir::MutImmutable => ok_if(Vec::new()),
-                        }
-                    }
-
-                    ty::BoundSized => ok_if(Vec::new()),
+    fn copy_conditions(&mut self, obligation: &TraitObligation<'tcx>)
+                     -> BuiltinImplConditions<'tcx>
+    {
+        // NOTE: binder moved to (*)
+        let self_ty = self.infcx.shallow_resolve(
+            obligation.predicate.skip_binder().self_ty());
 
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-                }
-            }
+        use self::BuiltinImplConditions::{Ambiguous, None, Never, Where};
 
-            ty::TyArray(element_ty, _) => {
-                // [T; n]
-                match bound {
-                    ty::BoundCopy => ok_if(vec![element_ty]),
-                    ty::BoundSized => ok_if(Vec::new()),
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-                }
+        match self_ty.sty {
+            ty::TyInfer(ty::IntVar(_)) | ty::TyInfer(ty::FloatVar(_)) |
+            ty::TyUint(_) | ty::TyInt(_) | ty::TyBool | ty::TyFloat(_) |
+            ty::TyFnDef(..) | ty::TyFnPtr(_) | ty::TyChar |
+            ty::TyRawPtr(..) | ty::TyError |
+            ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutImmutable }) => {
+                Where(ty::Binder(Vec::new()))
             }
 
-            ty::TyStr | ty::TySlice(_) => {
-                match bound {
-                    ty::BoundSync | ty::BoundSend => {
-                        bug!("Send/Sync shouldn't occur in builtin_bounds()");
-                    }
-
-                    ty::BoundCopy | ty::BoundSized => Err(Unimplemented),
-                }
+            ty::TyBox(_) | ty::TyTrait(..) | ty::TyStr | ty::TySlice(..) |
+            ty::TyClosure(..) |
+            ty::TyRef(_, ty::TypeAndMut { ty: _, mutbl: hir::MutMutable }) => {
+                Never
             }
 
-            // (T1, ..., Tn) -- meets any bound that all of T1...Tn meet
-            ty::TyTuple(ref tys) => ok_if(tys.clone()),
-
-            ty::TyClosure(_, ref substs) => {
-                // FIXME -- This case is tricky. In the case of by-ref
-                // closures particularly, we need the results of
-                // inference to decide how to reflect the type of each
-                // upvar (the upvar may have type `T`, but the runtime
-                // type could be `&mut`, `&`, or just `T`). For now,
-                // though, we'll do this unsoundly and assume that all
-                // captures are by value. Really what we ought to do
-                // is reserve judgement and then intertwine this
-                // analysis with closure inference.
-
-                // Unboxed closures shouldn't be
-                // implicitly copyable
-                if bound == ty::BoundCopy {
-                    return Ok(ParameterBuiltin);
-                }
-
-                // Upvars are always local variables or references to
-                // local variables, and local variables cannot be
-                // unsized, so the closure struct as a whole must be
-                // Sized.
-                if bound == ty::BoundSized {
-                    return ok_if(Vec::new());
-                }
-
-                ok_if(substs.upvar_tys.clone())
+            ty::TyArray(element_ty, _) => {
+                // (*) binder moved here
+                Where(ty::Binder(vec![element_ty]))
             }
 
-            ty::TyStruct(def, substs) | ty::TyEnum(def, substs) => {
-                let types: Vec<Ty> = def.all_fields().map(|f| {
-                    f.ty(self.tcx(), substs)
-                }).collect();
-                nominal(bound, types)
+            ty::TyTuple(ref tys) => {
+                // (*) binder moved here
+                Where(ty::Binder(tys.clone()))
             }
 
-            ty::TyProjection(_) | ty::TyParam(_) => {
-                // Note: A type parameter is only considered to meet a
-                // particular bound if there is a where clause telling
-                // us that it does, and that case is handled by
-                // `assemble_candidates_from_caller_bounds()`.
-                Ok(ParameterBuiltin)
+            ty::TyStruct(..) | ty::TyEnum(..) | ty::TyProjection(..) | ty::TyParam(..) => {
+                // Fallback to whatever user-defined impls exist in this case.
+                None
             }
 
             ty::TyInfer(ty::TyVar(_)) => {
                 // Unbound type variable. Might or might not have
                 // applicable impls and so forth, depending on what
                 // those type variables wind up being bound to.
-                debug!("assemble_builtin_bound_candidates: ambiguous builtin");
-                Ok(AmbiguousBuiltin)
+                Ambiguous
             }
 
-            ty::TyError => ok_if(Vec::new()),
-
             ty::TyInfer(ty::FreshTy(_))
             | ty::TyInfer(ty::FreshIntTy(_))
             | ty::TyInfer(ty::FreshFloatTy(_)) => {
                 bug!("asked to assemble builtin bounds of unexpected type: {:?}",
                      self_ty);
             }
-        };
-
-        fn ok_if<'tcx>(v: Vec<Ty<'tcx>>)
-                       -> Result<BuiltinBoundConditions<'tcx>, SelectionError<'tcx>> {
-            Ok(If(ty::Binder(v)))
-        }
-
-        fn nominal<'cx, 'tcx>(bound: ty::BuiltinBound,
-                              types: Vec<Ty<'tcx>>)
-                              -> Result<BuiltinBoundConditions<'tcx>, SelectionError<'tcx>>
-        {
-            // First check for markers and other nonsense.
-            match bound {
-                // Fallback to whatever user-defined impls exist in this case.
-                ty::BoundCopy => Ok(ParameterBuiltin),
-
-                // Sized if all the component types are sized.
-                ty::BoundSized => ok_if(types),
-
-                // Shouldn't be coming through here.
-                ty::BoundSend | ty::BoundSync => bug!(),
-            }
         }
     }
 
@@ -1916,20 +1823,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     }
 
     fn collect_predicates_for_types(&mut self,
-                                    obligation: &TraitObligation<'tcx>,
+                                    cause: ObligationCause<'tcx>,
+                                    recursion_depth: usize,
                                     trait_def_id: DefId,
                                     types: ty::Binder<Vec<Ty<'tcx>>>)
                                     -> Vec<PredicateObligation<'tcx>>
     {
-        let derived_cause = match self.tcx().lang_items.to_builtin_kind(trait_def_id) {
-            Some(_) => {
-                self.derived_cause(obligation, BuiltinDerivedObligation)
-            },
-            None => {
-                self.derived_cause(obligation, ImplDerivedObligation)
-            }
-        };
-
         // Because the types were potentially derived from
         // higher-ranked obligations they may reference late-bound
         // regions. For example, `for<'a> Foo<&'a int> : Copy` would
@@ -1944,40 +1843,28 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
         // 2. Produce something like `&'0 int : Copy`
         // 3. Re-bind the regions back to `for<'a> &'a int : Copy`
 
-        // Move the binder into the individual types
-        let bound_types: Vec<ty::Binder<Ty<'tcx>>> =
-            types.skip_binder()
-                 .iter()
-                 .map(|&nested_ty| ty::Binder(nested_ty))
-                 .collect();
+        types.skip_binder().into_iter().flat_map(|ty| { // binder moved -\
+            let ty: ty::Binder<Ty<'tcx>> = ty::Binder(ty); // <----------/
 
-        // For each type, produce a vector of resulting obligations
-        let obligations: Result<Vec<Vec<_>>, _> = bound_types.iter().map(|nested_ty| {
-            self.infcx.commit_if_ok(|snapshot| {
+            self.infcx.in_snapshot(|snapshot| {
                 let (skol_ty, skol_map) =
-                    self.infcx().skolemize_late_bound_regions(nested_ty, snapshot);
+                    self.infcx().skolemize_late_bound_regions(&ty, snapshot);
                 let Normalized { value: normalized_ty, mut obligations } =
                     project::normalize_with_depth(self,
-                                                  obligation.cause.clone(),
-                                                  obligation.recursion_depth + 1,
+                                                  cause.clone(),
+                                                  recursion_depth,
                                                   &skol_ty);
                 let skol_obligation =
                     util::predicate_for_trait_def(self.tcx(),
-                                                  derived_cause.clone(),
+                                                  cause.clone(),
                                                   trait_def_id,
-                                                  obligation.recursion_depth + 1,
+                                                  recursion_depth,
                                                   normalized_ty,
                                                   vec![]);
                 obligations.push(skol_obligation);
-                Ok(self.infcx().plug_leaks(skol_map, snapshot, &obligations))
+                self.infcx().plug_leaks(skol_map, snapshot, &obligations)
             })
-        }).collect();
-
-        // Flatten those vectors (couldn't do it above due `collect`)
-        match obligations {
-            Ok(obligations) => obligations.into_iter().flat_map(|o| o).collect(),
-            Err(ErrorReported) => Vec::new(),
-        }
+        }).collect()
     }
 
     ///////////////////////////////////////////////////////////////////////////
@@ -1997,9 +1884,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                candidate);
 
         match candidate {
-            BuiltinCandidate(builtin_bound) => {
+            BuiltinCandidate { has_nested } => {
                 Ok(VtableBuiltin(
-                    self.confirm_builtin_candidate(obligation, builtin_bound)?))
+                    self.confirm_builtin_candidate(obligation, has_nested)))
             }
 
             ParamCandidate(param) => {
@@ -2018,9 +1905,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
             }
 
             ImplCandidate(impl_def_id) => {
-                let vtable_impl =
-                    self.confirm_impl_candidate(obligation, impl_def_id)?;
-                Ok(VtableImpl(vtable_impl))
+                Ok(VtableImpl(self.confirm_impl_candidate(obligation, impl_def_id)))
             }
 
             ClosureCandidate(closure_def_id, substs, kind) => {
@@ -2064,14 +1949,12 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_projection_candidate(&mut self,
                                     obligation: &TraitObligation<'tcx>)
     {
-        let _: Result<(),()> =
-            self.infcx.commit_if_ok(|snapshot| {
-                let result =
-                    self.match_projection_obligation_against_bounds_from_trait(obligation,
-                                                                               snapshot);
-                assert!(result);
-                Ok(())
-            });
+        self.infcx.in_snapshot(|snapshot| {
+            let result =
+                self.match_projection_obligation_against_bounds_from_trait(obligation,
+                                                                           snapshot);
+            assert!(result);
+        })
     }
 
     fn confirm_param_candidate(&mut self,
@@ -2099,45 +1982,40 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
     fn confirm_builtin_candidate(&mut self,
                                  obligation: &TraitObligation<'tcx>,
-                                 bound: ty::BuiltinBound)
-                                 -> Result<VtableBuiltinData<PredicateObligation<'tcx>>,
-                                           SelectionError<'tcx>>
+                                 has_nested: bool)
+                                 -> VtableBuiltinData<PredicateObligation<'tcx>>
     {
-        debug!("confirm_builtin_candidate({:?})",
-               obligation);
-
-        match self.builtin_bound(bound, obligation)? {
-            If(nested) => Ok(self.vtable_builtin_data(obligation, bound, nested)),
-            AmbiguousBuiltin | ParameterBuiltin => {
-                span_bug!(
-                    obligation.cause.span,
-                    "builtin bound for {:?} was ambig",
-                    obligation);
-            }
-        }
-    }
-
-    fn vtable_builtin_data(&mut self,
-                           obligation: &TraitObligation<'tcx>,
-                           bound: ty::BuiltinBound,
-                           nested: ty::Binder<Vec<Ty<'tcx>>>)
-                           -> VtableBuiltinData<PredicateObligation<'tcx>>
-    {
-        debug!("vtable_builtin_data(obligation={:?}, bound={:?}, nested={:?})",
-               obligation, bound, nested);
+        debug!("confirm_builtin_candidate({:?}, {:?})",
+               obligation, has_nested);
+
+        let obligations = if has_nested {
+            let trait_def = obligation.predicate.def_id();
+            let conditions = match trait_def {
+                _ if Some(trait_def) == self.tcx().lang_items.sized_trait() => {
+                    self.sized_conditions(obligation)
+                }
+                _ if Some(trait_def) == self.tcx().lang_items.copy_trait() => {
+                    self.copy_conditions(obligation)
+                }
+                _ => bug!("unexpected builtin trait {:?}", trait_def)
+            };
+            let nested = match conditions {
+                BuiltinImplConditions::Where(nested) => nested,
+                _ => bug!("obligation {:?} had matched a builtin impl but now doesn't",
+                          obligation)
+            };
 
-        let trait_def = match self.tcx().lang_items.from_builtin_kind(bound) {
-            Ok(def_id) => def_id,
-            Err(_) => {
-                bug!("builtin trait definition not found");
-            }
+            let cause = self.derived_cause(obligation, BuiltinDerivedObligation);
+            self.collect_predicates_for_types(cause,
+                                              obligation.recursion_depth+1,
+                                              trait_def,
+                                              nested)
+        } else {
+            vec![]
         };
 
-        let obligations = self.collect_predicates_for_types(obligation, trait_def, nested);
-
-        debug!("vtable_builtin_data: obligations={:?}",
+        debug!("confirm_builtin_candidate: obligations={:?}",
                obligations);
-
         VtableBuiltinData { nested: obligations }
     }
 
@@ -2205,28 +2083,31 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
                            nested: ty::Binder<Vec<Ty<'tcx>>>)
                            -> VtableDefaultImplData<PredicateObligation<'tcx>>
     {
-        debug!("vtable_default_impl_data: nested={:?}", nested);
+        debug!("vtable_default_impl: nested={:?}", nested);
 
-        let mut obligations = self.collect_predicates_for_types(obligation,
-                                                                trait_def_id,
-                                                                nested);
+        let cause = self.derived_cause(obligation, BuiltinDerivedObligation);
+        let mut obligations = self.collect_predicates_for_types(
+            cause,
+            obligation.recursion_depth+1,
+            trait_def_id,
+            nested);
 
-        let trait_obligations: Result<Vec<_>,()> = self.infcx.commit_if_ok(|snapshot| {
+        let trait_obligations = self.infcx.in_snapshot(|snapshot| {
             let poly_trait_ref = obligation.predicate.to_poly_trait_ref();
             let (trait_ref, skol_map) =
                 self.infcx().skolemize_late_bound_regions(&poly_trait_ref, snapshot);
-            Ok(self.impl_or_trait_obligations(obligation.cause.clone(),
-                                              obligation.recursion_depth + 1,
-                                              trait_def_id,
-                                              &trait_ref.substs,
-                                              skol_map,
-                                              snapshot))
+            let cause = self.derived_cause(obligation, ImplDerivedObligation);
+            self.impl_or_trait_obligations(cause,
+                                           obligation.recursion_depth + 1,
+                                           trait_def_id,
+                                           &trait_ref.substs,
+                                           skol_map,
+                                           snapshot)
         });
 
-        // no Errors in that code above
-        obligations.append(&mut trait_obligations.unwrap());
+        obligations.extend(trait_obligations);
 
-        debug!("vtable_default_impl_data: obligations={:?}", obligations);
+        debug!("vtable_default_impl: obligations={:?}", obligations);
 
         VtableDefaultImplData {
             trait_def_id: trait_def_id,
@@ -2237,8 +2118,7 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
     fn confirm_impl_candidate(&mut self,
                               obligation: &TraitObligation<'tcx>,
                               impl_def_id: DefId)
-                              -> Result<VtableImplData<'tcx, PredicateObligation<'tcx>>,
-                                        SelectionError<'tcx>>
+                              -> VtableImplData<'tcx, PredicateObligation<'tcx>>
     {
         debug!("confirm_impl_candidate({:?},{:?})",
                obligation,
@@ -2246,13 +2126,15 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
         // First, create the substitutions by matching the impl again,
         // this time not in a probe.
-        self.infcx.commit_if_ok(|snapshot| {
+        self.infcx.in_snapshot(|snapshot| {
             let (substs, skol_map) =
                 self.rematch_impl(impl_def_id, obligation,
                                   snapshot);
             debug!("confirm_impl_candidate substs={:?}", substs);
-            Ok(self.vtable_impl(impl_def_id, substs, obligation.cause.clone(),
-                                obligation.recursion_depth + 1, skol_map, snapshot))
+            let cause = self.derived_cause(obligation, ImplDerivedObligation);
+            self.vtable_impl(impl_def_id, substs, cause,
+                             obligation.recursion_depth + 1,
+                             skol_map, snapshot)
         })
     }
 
@@ -2507,9 +2389,16 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> {
 
             // T -> Trait.
             (_, &ty::TyTrait(ref data)) => {
-                let object_did = data.principal_def_id();
-                if !object_safety::is_object_safe(tcx, object_did) {
-                    return Err(TraitNotObjectSafe(object_did));
+                let mut object_dids = Some(data.principal_def_id()).into_iter();
+                // FIXME(#33243)
+//                    data.bounds.builtin_bounds.iter().flat_map(|bound| {
+//                        tcx.lang_items.from_builtin_kind(bound).ok()
+//                    })
+//                    .chain(Some(data.principal_def_id()));
+                if let Some(did) = object_dids.find(|did| {
+                    !object_safety::is_object_safe(tcx, *did)
+                }) {
+                    return Err(TraitNotObjectSafe(did))
                 }
 
                 let cause = ObligationCause::new(obligation.cause.span,
diff --git a/src/librustc/traits/util.rs b/src/librustc/traits/util.rs
index 90def00be07..d82f9d7549d 100644
--- a/src/librustc/traits/util.rs
+++ b/src/librustc/traits/util.rs
@@ -18,6 +18,39 @@ use util::nodemap::FnvHashSet;
 
 use super::{Obligation, ObligationCause, PredicateObligation, SelectionContext, Normalized};
 
+fn anonymize_predicate<'tcx>(tcx: &TyCtxt<'tcx>, pred: &ty::Predicate<'tcx>)
+                             -> ty::Predicate<'tcx> {
+    match *pred {
+        ty::Predicate::Trait(ref data) =>
+            ty::Predicate::Trait(tcx.anonymize_late_bound_regions(data)),
+
+        ty::Predicate::Rfc1592(ref data) =>
+            ty::Predicate::Rfc1592(Box::new(anonymize_predicate(tcx, data))),
+
+        ty::Predicate::Equate(ref data) =>
+            ty::Predicate::Equate(tcx.anonymize_late_bound_regions(data)),
+
+        ty::Predicate::RegionOutlives(ref data) =>
+            ty::Predicate::RegionOutlives(tcx.anonymize_late_bound_regions(data)),
+
+        ty::Predicate::TypeOutlives(ref data) =>
+            ty::Predicate::TypeOutlives(tcx.anonymize_late_bound_regions(data)),
+
+        ty::Predicate::Projection(ref data) =>
+            ty::Predicate::Projection(tcx.anonymize_late_bound_regions(data)),
+
+        ty::Predicate::WellFormed(data) =>
+            ty::Predicate::WellFormed(data),
+
+        ty::Predicate::ObjectSafe(data) =>
+            ty::Predicate::ObjectSafe(data),
+
+        ty::Predicate::ClosureKind(closure_def_id, kind) =>
+            ty::Predicate::ClosureKind(closure_def_id, kind)
+    }
+}
+
+
 struct PredicateSet<'a,'tcx:'a> {
     tcx: &'a TyCtxt<'tcx>,
     set: FnvHashSet<ty::Predicate<'tcx>>,
@@ -39,32 +72,7 @@ impl<'a,'tcx> PredicateSet<'a,'tcx> {
         //
         // to be considered equivalent. So normalize all late-bound
         // regions before we throw things into the underlying set.
-        let normalized_pred = match *pred {
-            ty::Predicate::Trait(ref data) =>
-                ty::Predicate::Trait(self.tcx.anonymize_late_bound_regions(data)),
-
-            ty::Predicate::Equate(ref data) =>
-                ty::Predicate::Equate(self.tcx.anonymize_late_bound_regions(data)),
-
-            ty::Predicate::RegionOutlives(ref data) =>
-                ty::Predicate::RegionOutlives(self.tcx.anonymize_late_bound_regions(data)),
-
-            ty::Predicate::TypeOutlives(ref data) =>
-                ty::Predicate::TypeOutlives(self.tcx.anonymize_late_bound_regions(data)),
-
-            ty::Predicate::Projection(ref data) =>
-                ty::Predicate::Projection(self.tcx.anonymize_late_bound_regions(data)),
-
-            ty::Predicate::WellFormed(data) =>
-                ty::Predicate::WellFormed(data),
-
-            ty::Predicate::ObjectSafe(data) =>
-                ty::Predicate::ObjectSafe(data),
-
-            ty::Predicate::ClosureKind(closure_def_id, kind) =>
-                ty::Predicate::ClosureKind(closure_def_id, kind)
-        };
-        self.set.insert(normalized_pred)
+        self.set.insert(anonymize_predicate(self.tcx, pred))
     }
 }
 
@@ -143,6 +151,9 @@ impl<'cx, 'tcx> Elaborator<'cx, 'tcx> {
 
                 self.stack.extend(predicates);
             }
+            ty::Predicate::Rfc1592(..) => {
+                // Nothing to elaborate.
+            }
             ty::Predicate::WellFormed(..) => {
                 // Currently, we do not elaborate WF predicates,
                 // although we easily could.
diff --git a/src/librustc/ty/fold.rs b/src/librustc/ty/fold.rs
index 54223e16e17..8fcbc062952 100644
--- a/src/librustc/ty/fold.rs
+++ b/src/librustc/ty/fold.rs
@@ -329,7 +329,6 @@ impl<'tcx> TyCtxt<'tcx> {
         where F : FnMut(ty::BoundRegion) -> ty::Region,
               T : TypeFoldable<'tcx>,
     {
-        debug!("replace_late_bound_regions({:?})", value);
         let mut replacer = RegionReplacer::new(self, &mut f);
         let result = value.skip_binder().fold_with(&mut replacer);
         (result, replacer.map)
@@ -444,8 +443,6 @@ impl<'a, 'tcx> TypeFolder<'tcx> for RegionReplacer<'a, 'tcx>
     fn fold_region(&mut self, r: ty::Region) -> ty::Region {
         match r {
             ty::ReLateBound(debruijn, br) if debruijn.depth == self.current_depth => {
-                debug!("RegionReplacer.fold_region({:?}) folding region (current_depth={})",
-                       r, self.current_depth);
                 let fld_r = &mut self.fld_r;
                 let region = *self.map.entry(br).or_insert_with(|| fld_r(br));
                 if let ty::ReLateBound(debruijn1, br) = region {
diff --git a/src/librustc/ty/mod.rs b/src/librustc/ty/mod.rs
index bc342b235dd..3e3dae3b3e9 100644
--- a/src/librustc/ty/mod.rs
+++ b/src/librustc/ty/mod.rs
@@ -804,6 +804,9 @@ pub enum Predicate<'tcx> {
     /// would be the parameters in the `TypeSpace`.
     Trait(PolyTraitPredicate<'tcx>),
 
+    /// A predicate created by RFC1592
+    Rfc1592(Box<Predicate<'tcx>>),
+
     /// where `T1 == T2`.
     Equate(PolyEquatePredicate<'tcx>),
 
@@ -904,6 +907,8 @@ impl<'tcx> Predicate<'tcx> {
         match *self {
             Predicate::Trait(ty::Binder(ref data)) =>
                 Predicate::Trait(ty::Binder(data.subst(tcx, substs))),
+            Predicate::Rfc1592(ref pi) =>
+                Predicate::Rfc1592(Box::new(pi.subst_supertrait(tcx, trait_ref))),
             Predicate::Equate(ty::Binder(ref data)) =>
                 Predicate::Equate(ty::Binder(data.subst(tcx, substs))),
             Predicate::RegionOutlives(ty::Binder(ref data)) =>
@@ -1083,6 +1088,9 @@ impl<'tcx> Predicate<'tcx> {
             ty::Predicate::Trait(ref data) => {
                 data.0.trait_ref.substs.types.as_slice().to_vec()
             }
+            ty::Predicate::Rfc1592(ref data) => {
+                return data.walk_tys()
+            }
             ty::Predicate::Equate(ty::Binder(ref data)) => {
                 vec![data.0, data.1]
             }
@@ -1123,6 +1131,7 @@ impl<'tcx> Predicate<'tcx> {
             Predicate::Trait(ref t) => {
                 Some(t.to_poly_trait_ref())
             }
+            Predicate::Rfc1592(..) |
             Predicate::Projection(..) |
             Predicate::Equate(..) |
             Predicate::RegionOutlives(..) |
@@ -1498,6 +1507,7 @@ pub struct AdtDefData<'tcx, 'container: 'tcx> {
     pub variants: Vec<VariantDefData<'tcx, 'container>>,
     destructor: Cell<Option<DefId>>,
     flags: Cell<AdtFlags>,
+    sized_constraint: ivar::TyIVar<'tcx, 'container>,
 }
 
 impl<'tcx, 'container> PartialEq for AdtDefData<'tcx, 'container> {
@@ -1575,7 +1585,8 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
             did: did,
             variants: variants,
             flags: Cell::new(flags),
-            destructor: Cell::new(None)
+            destructor: Cell::new(None),
+            sized_constraint: ivar::TyIVar::new(),
         }
     }
 
@@ -1716,6 +1727,185 @@ impl<'tcx, 'container> AdtDefData<'tcx, 'container> {
             None => NoDtor,
         }
     }
+
+    /// Returns a simpler type such that `Self: Sized` if and only
+    /// if that type is Sized, or `TyErr` if this type is recursive.
+    ///
+    /// HACK: instead of returning a list of types, this function can
+    /// return a tuple. In that case, the result is Sized only if
+    /// all elements of the tuple are Sized.
+    ///
+    /// This is generally the `struct_tail` if this is a struct, or a
+    /// tuple of them if this is an enum.
+    ///
+    /// Oddly enough, checking that the sized-constraint is Sized is
+    /// actually more expressive than checking all members:
+    /// the Sized trait is inductive, so an associated type that references
+    /// Self would prevent its containing ADT from being Sized.
+    ///
+    /// Due to normalization being eager, this applies even if
+    /// the associated type is behind a pointer, e.g. issue #31299.
+    pub fn sized_constraint(&self, tcx: &ty::TyCtxt<'tcx>) -> Ty<'tcx> {
+        let dep_node = DepNode::SizedConstraint(self.did);
+        match self.sized_constraint.get(dep_node) {
+            None => {
+                let this = tcx.lookup_adt_def_master(self.did);
+                this.calculate_sized_constraint_inner(tcx, &mut Vec::new());
+                self.sized_constraint(tcx)
+            }
+            Some(ty) => ty
+        }
+    }
+}
+
+impl<'tcx> AdtDefData<'tcx, 'tcx> {
+    /// Calculates the Sized-constraint.
+    ///
+    /// As the Sized-constraint of enums can be a *set* of types,
+    /// the Sized-constraint may need to be a set also. Because introducing
+    /// a new type of IVar is currently a complex affair, the Sized-constraint
+    /// may be a tuple.
+    ///
+    /// In fact, there are only a few options for the constraint:
+    ///     - `bool`, if the type is always Sized
+    ///     - an obviously-unsized type
+    ///     - a type parameter or projection whose Sizedness can't be known
+    ///     - a tuple of type parameters or projections, if there are multiple
+    ///       such.
+    ///     - a TyError, if a type contained itself. The representability
+    ///       check should catch this case.
+    fn calculate_sized_constraint_inner(&'tcx self, tcx: &ty::TyCtxt<'tcx>,
+                                        stack: &mut Vec<AdtDefMaster<'tcx>>)
+    {
+
+        let dep_node = DepNode::SizedConstraint(self.did);
+
+        if self.sized_constraint.get(dep_node).is_some() {
+            return;
+        }
+
+        if stack.contains(&self) {
+            debug!("calculate_sized_constraint: {:?} is recursive", self);
+            // This should be reported as an error by `check_representable`.
+            //
+            // Consider the type as Sized in the meanwhile to avoid
+            // further errors.
+            self.sized_constraint.fulfill(dep_node, tcx.types.err);
+            return;
+        }
+
+        stack.push(self);
+
+        let tys : Vec<_> =
+            self.variants.iter().flat_map(|v| {
+                v.fields.last()
+            }).flat_map(|f| {
+                self.sized_constraint_for_ty(tcx, stack, f.unsubst_ty())
+            }).collect();
+
+        let self_ = stack.pop().unwrap();
+        assert_eq!(self_, self);
+
+        let ty = match tys.len() {
+            _ if tys.references_error() => tcx.types.err,
+            0 => tcx.types.bool,
+            1 => tys[0],
+            _ => tcx.mk_tup(tys)
+        };
+
+        match self.sized_constraint.get(dep_node) {
+            Some(old_ty) => {
+                debug!("calculate_sized_constraint: {:?} recurred", self);
+                assert_eq!(old_ty, tcx.types.err)
+            }
+            None => {
+                debug!("calculate_sized_constraint: {:?} => {:?}", self, ty);
+                self.sized_constraint.fulfill(dep_node, ty)
+            }
+        }
+    }
+
+    fn sized_constraint_for_ty(
+        &'tcx self,
+        tcx: &ty::TyCtxt<'tcx>,
+        stack: &mut Vec<AdtDefMaster<'tcx>>,
+        ty: Ty<'tcx>
+    ) -> Vec<Ty<'tcx>> {
+        let result = match ty.sty {
+            TyBool | TyChar | TyInt(..) | TyUint(..) | TyFloat(..) |
+            TyBox(..) | TyRawPtr(..) | TyRef(..) | TyFnDef(..) | TyFnPtr(_) |
+            TyArray(..) | TyClosure(..) => {
+                vec![]
+            }
+
+            TyStr | TyTrait(..) | TySlice(_) | TyError => {
+                // these are never sized - return the target type
+                vec![ty]
+            }
+
+            TyTuple(ref tys) => {
+                // FIXME(#33242) we only need to constrain the last field
+                tys.iter().flat_map(|ty| {
+                    self.sized_constraint_for_ty(tcx, stack, ty)
+                }).collect()
+            }
+
+            TyEnum(adt, substs) | TyStruct(adt, substs) => {
+                // recursive case
+                let adt = tcx.lookup_adt_def_master(adt.did);
+                adt.calculate_sized_constraint_inner(tcx, stack);
+                let adt_ty =
+                    adt.sized_constraint
+                    .unwrap(DepNode::SizedConstraint(adt.did))
+                    .subst(tcx, substs);
+                debug!("sized_constraint_for_ty({:?}) intermediate = {:?}",
+                       ty, adt_ty);
+                if let ty::TyTuple(ref tys) = adt_ty.sty {
+                    tys.iter().flat_map(|ty| {
+                        self.sized_constraint_for_ty(tcx, stack, ty)
+                    }).collect()
+                } else {
+                    self.sized_constraint_for_ty(tcx, stack, adt_ty)
+                }
+            }
+
+            TyProjection(..) => {
+                // must calculate explicitly.
+                // FIXME: consider special-casing always-Sized projections
+                vec![ty]
+            }
+
+            TyParam(..) => {
+                // perf hack: if there is a `T: Sized` bound, then
+                // we know that `T` is Sized and do not need to check
+                // it on the impl.
+
+                let sized_trait = match tcx.lang_items.sized_trait() {
+                    Some(x) => x,
+                    _ => return vec![ty]
+                };
+                let sized_predicate = Binder(TraitRef {
+                    def_id: sized_trait,
+                    substs: tcx.mk_substs(Substs::new_trait(
+                        vec![], vec![], ty
+                    ))
+                }).to_predicate();
+                let predicates = tcx.lookup_predicates(self.did).predicates;
+                if predicates.into_iter().any(|p| p == sized_predicate) {
+                    vec![]
+                } else {
+                    vec![ty]
+                }
+            }
+
+            TyInfer(..) => {
+                bug!("unexpected type `{:?}` in sized_constraint_for_ty",
+                     ty)
+            }
+        };
+        debug!("sized_constraint_for_ty({:?}) = {:?}", ty, result);
+        result
+    }
 }
 
 impl<'tcx, 'container> VariantDefData<'tcx, 'container> {
diff --git a/src/librustc/ty/structural_impls.rs b/src/librustc/ty/structural_impls.rs
index 4d64dd83071..ac3dfa82bd6 100644
--- a/src/librustc/ty/structural_impls.rs
+++ b/src/librustc/ty/structural_impls.rs
@@ -634,6 +634,8 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
         match *self {
             ty::Predicate::Trait(ref a) =>
                 ty::Predicate::Trait(a.fold_with(folder)),
+            ty::Predicate::Rfc1592(ref a) =>
+                ty::Predicate::Rfc1592(a.fold_with(folder)),
             ty::Predicate::Equate(ref binder) =>
                 ty::Predicate::Equate(binder.fold_with(folder)),
             ty::Predicate::RegionOutlives(ref binder) =>
@@ -654,6 +656,7 @@ impl<'tcx> TypeFoldable<'tcx> for ty::Predicate<'tcx> {
     fn super_visit_with<V: TypeVisitor<'tcx>>(&self, visitor: &mut V) -> bool {
         match *self {
             ty::Predicate::Trait(ref a) => a.visit_with(visitor),
+            ty::Predicate::Rfc1592(ref a) => a.visit_with(visitor),
             ty::Predicate::Equate(ref binder) => binder.visit_with(visitor),
             ty::Predicate::RegionOutlives(ref binder) => binder.visit_with(visitor),
             ty::Predicate::TypeOutlives(ref binder) => binder.visit_with(visitor),
diff --git a/src/librustc/ty/util.rs b/src/librustc/ty/util.rs
index 2e4f37f1cc1..b6bd8f5f55f 100644
--- a/src/librustc/ty/util.rs
+++ b/src/librustc/ty/util.rs
@@ -299,6 +299,7 @@ impl<'tcx> TyCtxt<'tcx> {
                 match predicate {
                     ty::Predicate::Projection(..) |
                     ty::Predicate::Trait(..) |
+                    ty::Predicate::Rfc1592(..) |
                     ty::Predicate::Equate(..) |
                     ty::Predicate::WellFormed(..) |
                     ty::Predicate::ObjectSafe(..) |
diff --git a/src/librustc/ty/wf.rs b/src/librustc/ty/wf.rs
index f93332e0773..609252f948a 100644
--- a/src/librustc/ty/wf.rs
+++ b/src/librustc/ty/wf.rs
@@ -94,6 +94,9 @@ pub fn predicate_obligations<'a,'tcx>(infcx: &InferCtxt<'a, 'tcx>,
         }
         ty::Predicate::ClosureKind(..) => {
         }
+        ty::Predicate::Rfc1592(ref data) => {
+            bug!("RFC1592 predicate `{:?}` in predicate_obligations", data);
+        }
     }
 
     wf.normalize()
@@ -155,6 +158,7 @@ pub fn implied_bounds<'a,'tcx>(
                 assert!(!obligation.has_escaping_regions());
                 match obligation.predicate {
                     ty::Predicate::Trait(..) |
+                    ty::Predicate::Rfc1592(..) |
                     ty::Predicate::Equate(..) |
                     ty::Predicate::Projection(..) |
                     ty::Predicate::ClosureKind(..) |
@@ -280,11 +284,35 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> {
         }
     }
 
+    fn require_sized(&mut self, subty: Ty<'tcx>, cause: traits::ObligationCauseCode<'tcx>,
+                     rfc1592: bool) {
+        if !subty.has_escaping_regions() {
+            let cause = self.cause(cause);
+            match traits::trait_ref_for_builtin_bound(self.infcx.tcx,
+                                                      ty::BoundSized,
+                                                      subty) {
+                Ok(trait_ref) => {
+                    let predicate = trait_ref.to_predicate();
+                    let predicate = if rfc1592 {
+                        ty::Predicate::Rfc1592(box predicate)
+                    } else {
+                        predicate
+                    };
+                    self.out.push(
+                        traits::Obligation::new(cause,
+                                                predicate));
+                }
+                Err(ErrorReported) => { }
+            }
+        }
+    }
+
     /// Push new obligations into `out`. Returns true if it was able
     /// to generate all the predicates needed to validate that `ty0`
     /// is WF. Returns false if `ty0` is an unresolved type variable,
     /// in which case we are not able to simplify at all.
     fn compute(&mut self, ty0: Ty<'tcx>) -> bool {
+        let tcx = self.infcx.tcx;
         let mut subtys = ty0.walk();
         while let Some(ty) = subtys.next() {
             match ty.sty {
@@ -301,23 +329,18 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> {
 
                 ty::TySlice(subty) |
                 ty::TyArray(subty, _) => {
-                    if !subty.has_escaping_regions() {
-                        let cause = self.cause(traits::SliceOrArrayElem);
-                        match traits::trait_ref_for_builtin_bound(self.infcx.tcx,
-                                                                  ty::BoundSized,
-                                                                  subty) {
-                            Ok(trait_ref) => {
-                                self.out.push(
-                                    traits::Obligation::new(cause,
-                                                            trait_ref.to_predicate()));
-                            }
-                            Err(ErrorReported) => { }
+                    self.require_sized(subty, traits::SliceOrArrayElem, false);
+                }
+
+                ty::TyTuple(ref tys) => {
+                    if let Some((_last, rest)) = tys.split_last() {
+                        for elem in rest {
+                            self.require_sized(elem, traits::TupleElem, true);
                         }
                     }
                 }
 
                 ty::TyBox(_) |
-                ty::TyTuple(_) |
                 ty::TyRawPtr(_) => {
                     // simple cases that are WF if their type args are WF
                 }
@@ -374,10 +397,25 @@ impl<'a,'tcx> WfPredicates<'a,'tcx> {
                     // checking those
 
                     let cause = self.cause(traits::MiscObligation);
-                    self.out.push(
-                        traits::Obligation::new(
-                            cause,
-                            ty::Predicate::ObjectSafe(data.principal_def_id())));
+
+                    // FIXME(#33243): remove RFC1592
+                    self.out.push(traits::Obligation::new(
+                        cause.clone(),
+                        ty::Predicate::ObjectSafe(data.principal_def_id())
+                    ));
+                    let component_traits =
+                        data.bounds.builtin_bounds.iter().flat_map(|bound| {
+                            tcx.lang_items.from_builtin_kind(bound).ok()
+                        });
+//                        .chain(Some(data.principal_def_id()));
+                    self.out.extend(
+                        component_traits.map(|did| { traits::Obligation::new(
+                            cause.clone(),
+                            ty::Predicate::Rfc1592(
+                                box ty::Predicate::ObjectSafe(did)
+                            )
+                        )})
+                    );
                 }
 
                 // Inference variables are the complicated case, since we don't
diff --git a/src/librustc/util/ppaux.rs b/src/librustc/util/ppaux.rs
index 9b590ec8aa6..728306b25dd 100644
--- a/src/librustc/util/ppaux.rs
+++ b/src/librustc/util/ppaux.rs
@@ -459,6 +459,9 @@ impl<'tcx> fmt::Debug for ty::Predicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             ty::Predicate::Trait(ref a) => write!(f, "{:?}", a),
+            ty::Predicate::Rfc1592(ref a) => {
+                write!(f, "RFC1592({:?})", a)
+            }
             ty::Predicate::Equate(ref pair) => write!(f, "{:?}", pair),
             ty::Predicate::RegionOutlives(ref pair) => write!(f, "{:?}", pair),
             ty::Predicate::TypeOutlives(ref pair) => write!(f, "{:?}", pair),
@@ -493,7 +496,7 @@ impl fmt::Debug for ty::BoundRegion {
             BrAnon(n) => write!(f, "BrAnon({:?})", n),
             BrFresh(n) => write!(f, "BrFresh({:?})", n),
             BrNamed(did, name) => {
-                write!(f, "BrNamed({:?}, {:?})", did, name)
+                write!(f, "BrNamed({:?}:{:?}, {:?})", did.krate, did.index, name)
             }
             BrEnv => "BrEnv".fmt(f),
         }
@@ -1056,6 +1059,7 @@ impl<'tcx> fmt::Display for ty::Predicate<'tcx> {
     fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
         match *self {
             ty::Predicate::Trait(ref data) => write!(f, "{}", data),
+            ty::Predicate::Rfc1592(ref data) => write!(f, "{}", data),
             ty::Predicate::Equate(ref predicate) => write!(f, "{}", predicate),
             ty::Predicate::RegionOutlives(ref predicate) => write!(f, "{}", predicate),
             ty::Predicate::TypeOutlives(ref predicate) => write!(f, "{}", predicate),
diff --git a/src/librustc_back/sha2.rs b/src/librustc_back/sha2.rs
index ba8107e03c9..26f512e0613 100644
--- a/src/librustc_back/sha2.rs
+++ b/src/librustc_back/sha2.rs
@@ -42,7 +42,7 @@ fn read_u32v_be(dst: &mut[u32], input: &[u8]) {
     }
 }
 
-trait ToBits {
+trait ToBits: Sized {
     /// Convert the value in bytes to the number of bits, a tuple where the 1st item is the
     /// high-order value and the 2nd item is the low order value.
     fn to_bits(self) -> (Self, Self);
diff --git a/src/librustc_lint/lib.rs b/src/librustc_lint/lib.rs
index e7c9097a56a..e0abe1aebd2 100644
--- a/src/librustc_lint/lib.rs
+++ b/src/librustc_lint/lib.rs
@@ -190,6 +190,14 @@ pub fn register_builtins(store: &mut lint::LintStore, sess: Option<&Session>) {
             id: LintId::of(ILLEGAL_STRUCT_OR_ENUM_CONSTANT_PATTERN),
             reference: "RFC 1445 <https://github.com/rust-lang/rfcs/pull/1445>",
         },
+        FutureIncompatibleInfo {
+            id: LintId::of(UNSIZED_IN_TUPLE),
+            reference: "issue #33242 <https://github.com/rust-lang/rust/issues/33242>",
+        },
+        FutureIncompatibleInfo {
+            id: LintId::of(OBJECT_UNSAFE_FRAGMENT),
+            reference: "issue #33243 <https://github.com/rust-lang/rust/issues/33243>",
+        }
         ]);
 
     // We have one lint pass defined specially
diff --git a/src/librustc_metadata/tyencode.rs b/src/librustc_metadata/tyencode.rs
index 61d055d4d51..57aa347847e 100644
--- a/src/librustc_metadata/tyencode.rs
+++ b/src/librustc_metadata/tyencode.rs
@@ -449,6 +449,9 @@ pub fn enc_predicate<'a, 'tcx>(w: &mut Cursor<Vec<u8>>,
                                p: &ty::Predicate<'tcx>)
 {
     match *p {
+        ty::Predicate::Rfc1592(..) => {
+            bug!("RFC1592 predicate in metadata `{:?}`", p);
+        }
         ty::Predicate::Trait(ref trait_ref) => {
             write!(w, "t");
             enc_trait_ref(w, cx, trait_ref.0.trait_ref);
diff --git a/src/librustc_passes/consts.rs b/src/librustc_passes/consts.rs
index dede4d2a42a..6fb9739fca4 100644
--- a/src/librustc_passes/consts.rs
+++ b/src/librustc_passes/consts.rs
@@ -277,6 +277,9 @@ impl<'a, 'tcx> CheckCrateVisitor<'a, 'tcx> {
                 traits::report_fulfillment_errors(&infcx, errors);
             }
         }
+        if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) {
+            traits::report_fulfillment_errors_as_warnings(&infcx, errors, e.id);
+        }
     }
 }
 
diff --git a/src/librustc_typeck/astconv.rs b/src/librustc_typeck/astconv.rs
index ac7745985e6..5e07011d5ba 100644
--- a/src/librustc_typeck/astconv.rs
+++ b/src/librustc_typeck/astconv.rs
@@ -1143,8 +1143,8 @@ fn make_object_type<'tcx>(this: &AstConv<'tcx>,
         traits::astconv_object_safety_violations(tcx, principal.def_id());
     if !object_safety_violations.is_empty() {
         traits::report_object_safety_error(
-            tcx, span, principal.def_id(), object_safety_violations)
-            .emit();
+            tcx, span, principal.def_id(), None, object_safety_violations)
+            .unwrap().emit();
         return tcx.types.err;
     }
 
diff --git a/src/librustc_typeck/check/closure.rs b/src/librustc_typeck/check/closure.rs
index 4ac7e3323ef..b84ded1ea7a 100644
--- a/src/librustc_typeck/check/closure.rs
+++ b/src/librustc_typeck/check/closure.rs
@@ -179,6 +179,7 @@ fn deduce_expectations_from_obligations<'a,'tcx>(
                 ty::Predicate::TypeOutlives(..) => None,
                 ty::Predicate::WellFormed(..) => None,
                 ty::Predicate::ObjectSafe(..) => None,
+                ty::Predicate::Rfc1592(..) => None,
 
                 // NB: This predicate is created by breaking down a
                 // `ClosureType: FnFoo()` predicate, where
diff --git a/src/librustc_typeck/check/coercion.rs b/src/librustc_typeck/check/coercion.rs
index f1c6868efd2..6c8d437f429 100644
--- a/src/librustc_typeck/check/coercion.rs
+++ b/src/librustc_typeck/check/coercion.rs
@@ -477,7 +477,7 @@ impl<'f, 'tcx> Coerce<'f, 'tcx> {
 
                 // Object safety violations or miscellaneous.
                 Err(err) => {
-                    report_selection_error(self.fcx.infcx(), &obligation, &err);
+                    report_selection_error(self.fcx.infcx(), &obligation, &err, None);
                     // Treat this like an obligation and follow through
                     // with the unsizing - the lack of a coercion should
                     // be silent, as it causes a type mismatch later.
diff --git a/src/librustc_typeck/check/dropck.rs b/src/librustc_typeck/check/dropck.rs
index 368b826b1bb..b9fda210454 100644
--- a/src/librustc_typeck/check/dropck.rs
+++ b/src/librustc_typeck/check/dropck.rs
@@ -114,6 +114,11 @@ fn ensure_drop_params_and_item_params_correspond<'tcx>(
         return Err(());
     }
 
+    if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(&infcx) {
+        traits::report_fulfillment_errors_as_warnings(&infcx, errors,
+                                                      drop_impl_node_id);
+    }
+
     let free_regions = FreeRegionMap::new();
     infcx.resolve_regions_and_report_errors(&free_regions, drop_impl_node_id);
     Ok(())
diff --git a/src/librustc_typeck/check/method/probe.rs b/src/librustc_typeck/check/method/probe.rs
index 2defbf0d33e..8a71debdf20 100644
--- a/src/librustc_typeck/check/method/probe.rs
+++ b/src/librustc_typeck/check/method/probe.rs
@@ -492,6 +492,7 @@ impl<'a,'tcx> ProbeContext<'a,'tcx> {
                     ty::Predicate::WellFormed(..) |
                     ty::Predicate::ObjectSafe(..) |
                     ty::Predicate::ClosureKind(..) |
+                    ty::Predicate::Rfc1592(..) |
                     ty::Predicate::TypeOutlives(..) => {
                         None
                     }
diff --git a/src/librustc_typeck/check/mod.rs b/src/librustc_typeck/check/mod.rs
index 385f04b8564..6599199c239 100644
--- a/src/librustc_typeck/check/mod.rs
+++ b/src/librustc_typeck/check/mod.rs
@@ -1989,13 +1989,18 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> {
         // upvar inference should have ensured that all deferred call
         // resolutions are handled by now.
         assert!(self.inh.deferred_call_resolutions.borrow().is_empty());
+        let infcx = self.infcx();
 
         self.select_all_obligations_and_apply_defaults();
 
         let mut fulfillment_cx = self.inh.fulfillment_cx.borrow_mut();
-        match fulfillment_cx.select_all_or_error(self.infcx()) {
+        match fulfillment_cx.select_all_or_error(infcx) {
             Ok(()) => { }
-            Err(errors) => { report_fulfillment_errors(self.infcx(), &errors); }
+            Err(errors) => { report_fulfillment_errors(infcx, &errors); }
+        }
+
+        if let Err(ref errors) = fulfillment_cx.select_rfc1592_obligations(infcx) {
+            traits::report_fulfillment_errors_as_warnings(infcx, errors, self.body_id);
         }
     }
 
diff --git a/src/librustc_typeck/collect.rs b/src/librustc_typeck/collect.rs
index c10488a03ef..4dd093e2e4b 100644
--- a/src/librustc_typeck/collect.rs
+++ b/src/librustc_typeck/collect.rs
@@ -450,6 +450,7 @@ impl<'tcx> GetTypeParameterBounds<'tcx> for ty::GenericPredicates<'tcx> {
                     ty::Predicate::TypeOutlives(ref data) => {
                         data.skip_binder().0.is_param(def.space, def.index)
                     }
+                    ty::Predicate::Rfc1592(..) |
                     ty::Predicate::Equate(..) |
                     ty::Predicate::RegionOutlives(..) |
                     ty::Predicate::WellFormed(..) |
diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs
index 0a606e1425c..398781e1405 100644
--- a/src/librustdoc/clean/mod.rs
+++ b/src/librustdoc/clean/mod.rs
@@ -866,6 +866,7 @@ impl<'a> Clean<WherePredicate> for ty::Predicate<'a> {
             Predicate::WellFormed(_) => panic!("not user writable"),
             Predicate::ObjectSafe(_) => panic!("not user writable"),
             Predicate::ClosureKind(..) => panic!("not user writable"),
+            Predicate::Rfc1592(..) => panic!("not user writable"),
         }
     }
 }
diff --git a/src/test/compile-fail/issue-17431-2.rs b/src/test/compile-fail/issue-17431-2.rs
index edbc8c82432..f39fb0e31c6 100644
--- a/src/test/compile-fail/issue-17431-2.rs
+++ b/src/test/compile-fail/issue-17431-2.rs
@@ -9,6 +9,7 @@
 // except according to those terms.
 
 struct Baz { q: Option<Foo> }
+//~^ ERROR recursive type `Baz` has infinite size
 
 struct Foo { q: Option<Baz> }
 //~^ ERROR recursive type `Foo` has infinite size
diff --git a/src/test/compile-fail/issue-20692.rs b/src/test/compile-fail/issue-20692.rs
index 62d775adac3..1c9e588cb2c 100644
--- a/src/test/compile-fail/issue-20692.rs
+++ b/src/test/compile-fail/issue-20692.rs
@@ -14,6 +14,7 @@ fn f<T: Array>(x: &T) {
     let _ = x
     //~^ ERROR `Array` cannot be made into an object
     //~| NOTE the trait cannot require that `Self : Sized`
+    //~| NOTE requirements on the impl of `std::ops::CoerceUnsized<&Array>`
     as
     &Array;
     //~^ ERROR `Array` cannot be made into an object
diff --git a/src/test/compile-fail/issue-26548.rs b/src/test/compile-fail/issue-26548.rs
index 28080ae09e5..2919b0b3cac 100644
--- a/src/test/compile-fail/issue-26548.rs
+++ b/src/test/compile-fail/issue-26548.rs
@@ -8,10 +8,11 @@
 // option. This file may not be copied, modified, or distributed
 // except according to those terms.
 
+// error-pattern: overflow representing the type `S`
+
 trait Mirror { type It: ?Sized; }
 impl<T: ?Sized> Mirror for T { type It = Self; }
 struct S(Option<<S as Mirror>::It>);
-//~^ ERROR recursive type `S` has infinite size
 
 fn main() {
     let _s = S(None);
diff --git a/src/test/compile-fail/issue-32963.rs b/src/test/compile-fail/issue-32963.rs
new file mode 100644
index 00000000000..c4e8f766117
--- /dev/null
+++ b/src/test/compile-fail/issue-32963.rs
@@ -0,0 +1,20 @@
+// 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.
+
+use std::mem;
+
+trait Misc {}
+
+fn size_of_copy<T: Copy+?Sized>() -> usize { mem::size_of::<T>() }
+
+fn main() {
+    size_of_copy::<Misc+Copy>();
+    //~^ ERROR `Misc + Copy: std::marker::Copy` is not satisfied
+}
diff --git a/src/test/compile-fail/kindck-copy.rs b/src/test/compile-fail/kindck-copy.rs
index 08b4e1a45f3..747fe2d2046 100644
--- a/src/test/compile-fail/kindck-copy.rs
+++ b/src/test/compile-fail/kindck-copy.rs
@@ -45,15 +45,15 @@ fn test<'a,T,U:Copy>(_: &'a isize) {
 
     // borrowed object types are generally ok
     assert_copy::<&'a Dummy>();
-    assert_copy::<&'a (Dummy+Copy)>();
-    assert_copy::<&'static (Dummy+Copy)>();
+    assert_copy::<&'a (Dummy+Send)>();
+    assert_copy::<&'static (Dummy+Send)>();
 
     // owned object types are not ok
     assert_copy::<Box<Dummy>>(); //~ ERROR : std::marker::Copy` is not satisfied
-    assert_copy::<Box<Dummy+Copy>>(); //~ ERROR : std::marker::Copy` is not satisfied
+    assert_copy::<Box<Dummy+Send>>(); //~ ERROR : std::marker::Copy` is not satisfied
 
     // mutable object types are not ok
-    assert_copy::<&'a mut (Dummy+Copy)>();  //~ ERROR : std::marker::Copy` is not satisfied
+    assert_copy::<&'a mut (Dummy+Send)>();  //~ ERROR : std::marker::Copy` is not satisfied
 
     // unsafe ptrs are ok
     assert_copy::<*const isize>();
diff --git a/src/test/compile-fail/range-1.rs b/src/test/compile-fail/range-1.rs
index 895d2450cfe..2a0773af73b 100644
--- a/src/test/compile-fail/range-1.rs
+++ b/src/test/compile-fail/range-1.rs
@@ -23,5 +23,4 @@ pub fn main() {
     let arr: &[_] = &[1, 2, 3];
     let range = *arr..;
     //~^ ERROR `[_]: std::marker::Sized` is not satisfied
-    //~| ERROR `[_]: std::marker::Sized` is not satisfied
 }
diff --git a/src/test/compile-fail/rfc1592-deprecated.rs b/src/test/compile-fail/rfc1592-deprecated.rs
new file mode 100644
index 00000000000..e766f977200
--- /dev/null
+++ b/src/test/compile-fail/rfc1592-deprecated.rs
@@ -0,0 +1,32 @@
+// 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.
+
+use std::fmt;
+
+#[deny(warnings)] trait Foo { fn foo(&self) -> (Self, Self); }
+//~^ ERROR the trait bound `Self: std::marker::Sized` is not satisfied
+//~| WARNING hard error
+
+impl<T: Copy> Foo for T {
+    fn foo(&self) -> (Self, Self) {
+        (*self, *self)
+    }
+}
+
+#[deny(warnings)]
+fn main() {
+    assert_eq!((11).foo(), (11, 11));
+
+    let junk: Box<fmt::Debug+Sized> = Box::new(42);
+    //~^ ERROR the trait cannot require that `Self : Sized`
+    //~| WARNING hard error
+    let f = format!("{:?}", junk);
+    assert_eq!(f, "42");
+}
diff --git a/src/test/compile-fail/sized-cycle-note.rs b/src/test/compile-fail/sized-cycle-note.rs
index 3d7c4868e96..712b4ac22f0 100644
--- a/src/test/compile-fail/sized-cycle-note.rs
+++ b/src/test/compile-fail/sized-cycle-note.rs
@@ -17,14 +17,9 @@
 // 2. it should elaborate the steps that led to the cycle.
 
 struct Baz { q: Option<Foo> }
-
+//~^ ERROR recursive type `Baz` has infinite size
 struct Foo { q: Option<Baz> }
 //~^ ERROR recursive type `Foo` has infinite size
-//~| NOTE type `Foo` is embedded within `std::option::Option<Foo>`...
-//~| NOTE ...which in turn is embedded within `std::option::Option<Foo>`...
-//~| NOTE ...which in turn is embedded within `Baz`...
-//~| NOTE ...which in turn is embedded within `std::option::Option<Baz>`...
-//~| NOTE ...which in turn is embedded within `Foo`, completing the cycle.
 
 impl Foo { fn bar(&self) {} }
 
diff --git a/src/test/compile-fail/unsized6.rs b/src/test/compile-fail/unsized6.rs
index 663cb0a1716..d40c12f67a0 100644
--- a/src/test/compile-fail/unsized6.rs
+++ b/src/test/compile-fail/unsized6.rs
@@ -14,9 +14,9 @@ trait T {}
 
 fn f1<X: ?Sized>(x: &X) {
     let _: X; // <-- this is OK, no bindings created, no initializer.
-    let _: (isize, (X, isize)); // same
+    let _: (isize, (X, isize));
     let y: X; //~ERROR `X: std::marker::Sized` is not satisfied
-    let y: (isize, (X, isize)); //~ERROR `X: std::marker::Sized` is not satisfied
+    let y: (isize, (X, usize)); //~ERROR `X: std::marker::Sized` is not satisfied
 }
 fn f2<X: ?Sized + T>(x: &X) {
     let y: X; //~ERROR `X: std::marker::Sized` is not satisfied
diff --git a/src/test/run-pass/issue-31299.rs b/src/test/run-pass/issue-31299.rs
new file mode 100644
index 00000000000..6c04e66068e
--- /dev/null
+++ b/src/test/run-pass/issue-31299.rs
@@ -0,0 +1,43 @@
+// Copyright 2012 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.
+
+// Regression test for #31299. This was generating an overflow error
+// because of eager normalization:
+//
+// proving `M: Sized` requires
+// - proving `PtrBack<Vec<M>>: Sized` requires
+//   - normalizing `Vec<<Vec<M> as Front>::Back>>: Sized` requires
+//     - proving `Vec<M>: Front` requires
+//       - `M: Sized` <-- cycle!
+//
+// If we skip the normalization step, though, everything goes fine.
+//
+// This could be fixed by implementing lazy normalization everywhere.
+//
+// However, we want this to work before then. For that, when checking
+// whether a type is Sized we only check that the tails are Sized. As
+// PtrBack does not have a tail, we don't need to normalize anything
+// and this compiles
+
+trait Front {
+    type Back;
+}
+
+impl<T> Front for Vec<T> {
+    type Back = Vec<T>;
+}
+
+struct PtrBack<T: Front>(Vec<T::Back>);
+
+struct M(PtrBack<Vec<M>>);
+
+fn main() {
+    std::mem::size_of::<M>();
+}
diff --git a/src/test/run-pass/rfc1592-deprecated.rs b/src/test/run-pass/rfc1592-deprecated.rs
new file mode 100644
index 00000000000..81bf0258789
--- /dev/null
+++ b/src/test/run-pass/rfc1592-deprecated.rs
@@ -0,0 +1,29 @@
+// 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.
+
+use std::fmt;
+
+trait Foo {
+    fn foo(&self) -> (Self, Self);
+}
+
+impl<T: Copy> Foo for T {
+    fn foo(&self) -> (Self, Self) {
+        (*self, *self)
+    }
+}
+
+fn main() {
+    assert_eq!((11).foo(), (11, 11));
+
+    let junk: Box<fmt::Debug+Sized> = Box::new(42);
+    let f = format!("{:?}", junk);
+    assert_eq!(f, "42");
+}