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();
+}