Merge pull request #34635 from alexcrichton/beta-next

Last minute backports to beta
diff --git a/mk/main.mk b/mk/main.mk
index 0864875..c47020c 100644
--- a/mk/main.mk
+++ b/mk/main.mk
@@ -18,7 +18,7 @@
 # An optional number to put after the label, e.g. '.2' -> '-beta.2'
 # NB Make sure it starts with a dot to conform to semver pre-release
 # versions (section 9)
-CFG_PRERELEASE_VERSION=.3
+CFG_PRERELEASE_VERSION=.4
 
 # Append a version-dependent hash to each library, so we can install different
 # versions in the same place
diff --git a/src/librustc/traits/object_safety.rs b/src/librustc/traits/object_safety.rs
index 8cafa77..ffa1530 100644
--- a/src/librustc/traits/object_safety.rs
+++ b/src/librustc/traits/object_safety.rs
@@ -228,9 +228,14 @@
     /// otherwise ensure that they cannot be used when `Self=Trait`.
     pub fn is_vtable_safe_method(self,
                                  trait_def_id: DefId,
-                                 method: &ty::Method<'tcx>)
+                                 method: &ty::Method<'gcx>)
                                  -> bool
     {
+        // Any method that has a `Self : Sized` requisite can't be called.
+        if self.generics_require_sized_self(&method.generics, &method.predicates) {
+            return false;
+        }
+
         self.virtual_call_violation_for_method(trait_def_id, method).is_none()
     }
 
diff --git a/src/librustc_const_eval/eval.rs b/src/librustc_const_eval/eval.rs
index 9db24fa..d0be7e2 100644
--- a/src/librustc_const_eval/eval.rs
+++ b/src/librustc_const_eval/eval.rs
@@ -556,51 +556,44 @@
     let result = match e.node {
       hir::ExprUnary(hir::UnNeg, ref inner) => {
         // unary neg literals already got their sign during creation
-        match inner.node {
-            hir::ExprLit(ref lit) => {
-                use syntax::ast::*;
-                use syntax::ast::LitIntType::*;
-                const I8_OVERFLOW: u64 = ::std::i8::MAX as u64 + 1;
-                const I16_OVERFLOW: u64 = ::std::i16::MAX as u64 + 1;
-                const I32_OVERFLOW: u64 = ::std::i32::MAX as u64 + 1;
-                const I64_OVERFLOW: u64 = ::std::i64::MAX as u64 + 1;
-                match (&lit.node, ety.map(|t| &t.sty)) {
-                    (&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) |
-                    (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
-                        return Ok(Integral(I8(::std::i8::MIN)))
-                    },
-                    (&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) |
-                    (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
-                        return Ok(Integral(I16(::std::i16::MIN)))
-                    },
-                    (&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) |
-                    (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
-                        return Ok(Integral(I32(::std::i32::MIN)))
-                    },
-                    (&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) |
-                    (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
-                        return Ok(Integral(I64(::std::i64::MIN)))
-                    },
-                    (&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) |
-                    (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
-                        match tcx.sess.target.int_type {
-                            IntTy::I32 => if n == I32_OVERFLOW {
-                                return Ok(Integral(Isize(Is32(::std::i32::MIN))));
-                            },
-                            IntTy::I64 => if n == I64_OVERFLOW {
-                                return Ok(Integral(Isize(Is64(::std::i64::MIN))));
-                            },
-                            _ => bug!(),
-                        }
-                    },
-                    _ => {},
-                }
-            },
-            hir::ExprUnary(hir::UnNeg, ref inner) => {
-                // skip `--$expr`
-                return eval_const_expr_partial(tcx, inner, ty_hint, fn_args);
-            },
-            _ => {},
+        if let hir::ExprLit(ref lit) = inner.node {
+            use syntax::ast::*;
+            use syntax::ast::LitIntType::*;
+            const I8_OVERFLOW: u64 = ::std::i8::MAX as u64 + 1;
+            const I16_OVERFLOW: u64 = ::std::i16::MAX as u64 + 1;
+            const I32_OVERFLOW: u64 = ::std::i32::MAX as u64 + 1;
+            const I64_OVERFLOW: u64 = ::std::i64::MAX as u64 + 1;
+            match (&lit.node, ety.map(|t| &t.sty)) {
+                (&LitKind::Int(I8_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I8))) |
+                (&LitKind::Int(I8_OVERFLOW, Signed(IntTy::I8)), _) => {
+                    return Ok(Integral(I8(::std::i8::MIN)))
+                },
+                (&LitKind::Int(I16_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I16))) |
+                (&LitKind::Int(I16_OVERFLOW, Signed(IntTy::I16)), _) => {
+                    return Ok(Integral(I16(::std::i16::MIN)))
+                },
+                (&LitKind::Int(I32_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I32))) |
+                (&LitKind::Int(I32_OVERFLOW, Signed(IntTy::I32)), _) => {
+                    return Ok(Integral(I32(::std::i32::MIN)))
+                },
+                (&LitKind::Int(I64_OVERFLOW, Unsuffixed), Some(&ty::TyInt(IntTy::I64))) |
+                (&LitKind::Int(I64_OVERFLOW, Signed(IntTy::I64)), _) => {
+                    return Ok(Integral(I64(::std::i64::MIN)))
+                },
+                (&LitKind::Int(n, Unsuffixed), Some(&ty::TyInt(IntTy::Is))) |
+                (&LitKind::Int(n, Signed(IntTy::Is)), _) => {
+                    match tcx.sess.target.int_type {
+                        IntTy::I32 => if n == I32_OVERFLOW {
+                            return Ok(Integral(Isize(Is32(::std::i32::MIN))));
+                        },
+                        IntTy::I64 => if n == I64_OVERFLOW {
+                            return Ok(Integral(Isize(Is64(::std::i64::MIN))));
+                        },
+                        _ => bug!(),
+                    }
+                },
+                _ => {},
+            }
         }
         match eval_const_expr_partial(tcx, &inner, ty_hint, fn_args)? {
           Float(f) => Float(-f),
diff --git a/src/librustc_data_structures/obligation_forest/mod.rs b/src/librustc_data_structures/obligation_forest/mod.rs
index b713b22..c079146 100644
--- a/src/librustc_data_structures/obligation_forest/mod.rs
+++ b/src/librustc_data_structures/obligation_forest/mod.rs
@@ -208,11 +208,17 @@
     ///
     /// This CAN be done in a snapshot
     pub fn register_obligation(&mut self, obligation: O) {
-        self.register_obligation_at(obligation, None)
+        // Ignore errors here - there is no guarantee of success.
+        let _ = self.register_obligation_at(obligation, None);
     }
 
-    fn register_obligation_at(&mut self, obligation: O, parent: Option<NodeIndex>) {
-        if self.done_cache.contains(obligation.as_predicate()) { return }
+    // returns Err(()) if we already know this obligation failed.
+    fn register_obligation_at(&mut self, obligation: O, parent: Option<NodeIndex>)
+                              -> Result<(), ()>
+    {
+        if self.done_cache.contains(obligation.as_predicate()) {
+            return Ok(())
+        }
 
         match self.waiting_cache.entry(obligation.as_predicate().clone()) {
             Entry::Occupied(o) => {
@@ -226,6 +232,11 @@
                         self.nodes[o.get().get()].dependents.push(parent);
                     }
                 }
+                if let NodeState::Error = self.nodes[o.get().get()].state.get() {
+                    Err(())
+                } else {
+                    Ok(())
+                }
             }
             Entry::Vacant(v) => {
                 debug!("register_obligation_at({:?}, {:?}) - ok",
@@ -233,8 +244,9 @@
                 v.insert(NodeIndex::new(self.nodes.len()));
                 self.cache_list.push(obligation.as_predicate().clone());
                 self.nodes.push(Node::new(parent, obligation));
+                Ok(())
             }
-        };
+        }
     }
 
     /// Convert all remaining obligations to the given error.
@@ -306,12 +318,19 @@
                 Ok(Some(children)) => {
                     // if we saw a Some(_) result, we are not (yet) stalled
                     stalled = false;
-                    for child in children {
-                        self.register_obligation_at(child,
-                                                    Some(NodeIndex::new(index)));
-                    }
-
                     self.nodes[index].state.set(NodeState::Success);
+
+                    for child in children {
+                        let st = self.register_obligation_at(
+                            child,
+                            Some(NodeIndex::new(index))
+                        );
+                        if let Err(()) = st {
+                            // error already reported - propagate it
+                            // to our node.
+                            self.error_at(index);
+                        }
+                    }
                 }
                 Err(err) => {
                     let backtrace = self.error_at(index);
diff --git a/src/librustc_data_structures/obligation_forest/test.rs b/src/librustc_data_structures/obligation_forest/test.rs
index 8eac889..a95b2b8 100644
--- a/src/librustc_data_structures/obligation_forest/test.rs
+++ b/src/librustc_data_structures/obligation_forest/test.rs
@@ -418,3 +418,43 @@
     let errors = forest.to_errors(());
     assert_eq!(errors.len(), 0);
 }
+
+#[test]
+fn simultaneous_register_and_error() {
+    // check that registering a failed obligation works correctly
+    let mut forest = ObligationForest::new();
+    forest.register_obligation("A");
+    forest.register_obligation("B");
+
+    let Outcome { completed: ok, errors: err, .. } =
+        forest.process_obligations(&mut C(|obligation| {
+            match *obligation {
+                "A" => Err("An error"),
+                "B" => Ok(Some(vec!["A"])),
+                _ => unreachable!(),
+            }
+        }, |_|{}));
+    assert_eq!(ok.len(), 0);
+    assert_eq!(err, vec![super::Error {
+        error: "An error",
+        backtrace: vec!["A"]
+    }]);
+
+    let mut forest = ObligationForest::new();
+    forest.register_obligation("B");
+    forest.register_obligation("A");
+
+    let Outcome { completed: ok, errors: err, .. } =
+        forest.process_obligations(&mut C(|obligation| {
+            match *obligation {
+                "A" => Err("An error"),
+                "B" => Ok(Some(vec!["A"])),
+                _ => unreachable!(),
+            }
+        }, |_|{}));
+    assert_eq!(ok.len(), 0);
+    assert_eq!(err, vec![super::Error {
+        error: "An error",
+        backtrace: vec!["A"]
+    }]);
+}
diff --git a/src/test/compile-fail/lint-type-overflow2.rs b/src/test/compile-fail/lint-type-overflow2.rs
index 9499d73..e99dfb9 100644
--- a/src/test/compile-fail/lint-type-overflow2.rs
+++ b/src/test/compile-fail/lint-type-overflow2.rs
@@ -15,6 +15,7 @@
 #[allow(unused_variables)]
 fn main() {
     let x2: i8 = --128; //~ error: literal out of range for i8
+    //~^ error: attempted to negate with overflow
 
     let x = -3.40282348e+38_f32; //~ error: literal out of range for f32
     let x =  3.40282348e+38_f32; //~ error: literal out of range for f32
diff --git a/src/test/run-pass/issue-34503.rs b/src/test/run-pass/issue-34503.rs
new file mode 100644
index 0000000..e621724
--- /dev/null
+++ b/src/test/run-pass/issue-34503.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.
+
+fn main() {
+    struct X;
+    trait Foo<T> {
+        fn foo(&self) where (T, Option<T>): Ord {}
+        fn bar(&self, x: &Option<T>) -> bool
+        where Option<T>: Ord { *x < *x }
+    }
+    impl Foo<X> for () {}
+    let _ = &() as &Foo<X>;
+}
diff --git a/src/test/run-pass/trait-object-exclusion.rs b/src/test/run-pass/trait-object-exclusion.rs
new file mode 100644
index 0000000..13b725b
--- /dev/null
+++ b/src/test/run-pass/trait-object-exclusion.rs
@@ -0,0 +1,28 @@
+// 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.
+
+trait Future: 'static {
+    // The requirement for Self: Sized must prevent instantiation of
+    // Future::forget in vtables, otherwise there's an infinite type
+    // recursion through <Map<...> as Future>::forget.
+    fn forget(self) where Self: Sized {
+        Box::new(Map(self)) as Box<Future>;
+    }
+}
+
+struct Map<A>(A);
+impl<A: Future> Future for Map<A> {}
+
+pub struct Promise;
+impl Future for Promise {}
+
+fn main() {
+    Promise.forget();
+}