mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-23 23:34:48 +00:00
fail obligations that depend on erroring obligations
Fix a bug where an obligation that depend on an erroring obligation would be regarded as successful, leading to global cache pollution and random lossage. Fixes #33723. Fixes #34503.
This commit is contained in:
parent
ea0dc92972
commit
201cdd33df
@ -208,11 +208,17 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
///
|
||||
/// 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 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
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 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
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 @@ impl<O: ForestObligation> ObligationForest<O> {
|
||||
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);
|
||||
|
@ -418,3 +418,43 @@ fn orphan() {
|
||||
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"]
|
||||
}]);
|
||||
}
|
||||
|
20
src/test/run-pass/issue-34503.rs
Normal file
20
src/test/run-pass/issue-34503.rs
Normal file
@ -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>;
|
||||
}
|
Loading…
Reference in New Issue
Block a user