mirror of
https://github.com/rust-lang/rust.git
synced 2024-11-24 07:44:10 +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
|
/// This CAN be done in a snapshot
|
||||||
pub fn register_obligation(&mut self, obligation: O) {
|
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>) {
|
// returns Err(()) if we already know this obligation failed.
|
||||||
if self.done_cache.contains(obligation.as_predicate()) { return }
|
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()) {
|
match self.waiting_cache.entry(obligation.as_predicate().clone()) {
|
||||||
Entry::Occupied(o) => {
|
Entry::Occupied(o) => {
|
||||||
@ -226,6 +232,11 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||||||
self.nodes[o.get().get()].dependents.push(parent);
|
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) => {
|
Entry::Vacant(v) => {
|
||||||
debug!("register_obligation_at({:?}, {:?}) - ok",
|
debug!("register_obligation_at({:?}, {:?}) - ok",
|
||||||
@ -233,8 +244,9 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||||||
v.insert(NodeIndex::new(self.nodes.len()));
|
v.insert(NodeIndex::new(self.nodes.len()));
|
||||||
self.cache_list.push(obligation.as_predicate().clone());
|
self.cache_list.push(obligation.as_predicate().clone());
|
||||||
self.nodes.push(Node::new(parent, obligation));
|
self.nodes.push(Node::new(parent, obligation));
|
||||||
|
Ok(())
|
||||||
|
}
|
||||||
}
|
}
|
||||||
};
|
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Convert all remaining obligations to the given error.
|
/// Convert all remaining obligations to the given error.
|
||||||
@ -306,12 +318,19 @@ impl<O: ForestObligation> ObligationForest<O> {
|
|||||||
Ok(Some(children)) => {
|
Ok(Some(children)) => {
|
||||||
// if we saw a Some(_) result, we are not (yet) stalled
|
// if we saw a Some(_) result, we are not (yet) stalled
|
||||||
stalled = false;
|
stalled = false;
|
||||||
for child in children {
|
|
||||||
self.register_obligation_at(child,
|
|
||||||
Some(NodeIndex::new(index)));
|
|
||||||
}
|
|
||||||
|
|
||||||
self.nodes[index].state.set(NodeState::Success);
|
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) => {
|
Err(err) => {
|
||||||
let backtrace = self.error_at(index);
|
let backtrace = self.error_at(index);
|
||||||
|
@ -418,3 +418,43 @@ fn orphan() {
|
|||||||
let errors = forest.to_errors(());
|
let errors = forest.to_errors(());
|
||||||
assert_eq!(errors.len(), 0);
|
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