Skip to content

Commit 1ab87b6

Browse files
authored
Auto merge of #34605 - arielb1:bug-in-the-jungle, r=eddyb
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. r? @eddyb since @nikomatsakis is on vacation beta-nominating because of the massive lossage potential (e.g. with `Copy` this could lead to random memory leaks), plus this is a regression.
2 parents e85adff + 201cdd3 commit 1ab87b6

File tree

3 files changed

+87
-8
lines changed

3 files changed

+87
-8
lines changed

src/librustc_data_structures/obligation_forest/mod.rs

+27-8
Original file line numberDiff line numberDiff line change
@@ -208,11 +208,17 @@ impl<O: ForestObligation> ObligationForest<O> {
208208
///
209209
/// This CAN be done in a snapshot
210210
pub fn register_obligation(&mut self, obligation: O) {
211-
self.register_obligation_at(obligation, None)
211+
// Ignore errors here - there is no guarantee of success.
212+
let _ = self.register_obligation_at(obligation, None);
212213
}
213214

214-
fn register_obligation_at(&mut self, obligation: O, parent: Option<NodeIndex>) {
215-
if self.done_cache.contains(obligation.as_predicate()) { return }
215+
// returns Err(()) if we already know this obligation failed.
216+
fn register_obligation_at(&mut self, obligation: O, parent: Option<NodeIndex>)
217+
-> Result<(), ()>
218+
{
219+
if self.done_cache.contains(obligation.as_predicate()) {
220+
return Ok(())
221+
}
216222

217223
match self.waiting_cache.entry(obligation.as_predicate().clone()) {
218224
Entry::Occupied(o) => {
@@ -226,15 +232,21 @@ impl<O: ForestObligation> ObligationForest<O> {
226232
self.nodes[o.get().get()].dependents.push(parent);
227233
}
228234
}
235+
if let NodeState::Error = self.nodes[o.get().get()].state.get() {
236+
Err(())
237+
} else {
238+
Ok(())
239+
}
229240
}
230241
Entry::Vacant(v) => {
231242
debug!("register_obligation_at({:?}, {:?}) - ok",
232243
obligation, parent);
233244
v.insert(NodeIndex::new(self.nodes.len()));
234245
self.cache_list.push(obligation.as_predicate().clone());
235246
self.nodes.push(Node::new(parent, obligation));
247+
Ok(())
236248
}
237-
};
249+
}
238250
}
239251

240252
/// Convert all remaining obligations to the given error.
@@ -306,12 +318,19 @@ impl<O: ForestObligation> ObligationForest<O> {
306318
Ok(Some(children)) => {
307319
// if we saw a Some(_) result, we are not (yet) stalled
308320
stalled = false;
321+
self.nodes[index].state.set(NodeState::Success);
322+
309323
for child in children {
310-
self.register_obligation_at(child,
311-
Some(NodeIndex::new(index)));
324+
let st = self.register_obligation_at(
325+
child,
326+
Some(NodeIndex::new(index))
327+
);
328+
if let Err(()) = st {
329+
// error already reported - propagate it
330+
// to our node.
331+
self.error_at(index);
332+
}
312333
}
313-
314-
self.nodes[index].state.set(NodeState::Success);
315334
}
316335
Err(err) => {
317336
let backtrace = self.error_at(index);

src/librustc_data_structures/obligation_forest/test.rs

+40
Original file line numberDiff line numberDiff line change
@@ -418,3 +418,43 @@ fn orphan() {
418418
let errors = forest.to_errors(());
419419
assert_eq!(errors.len(), 0);
420420
}
421+
422+
#[test]
423+
fn simultaneous_register_and_error() {
424+
// check that registering a failed obligation works correctly
425+
let mut forest = ObligationForest::new();
426+
forest.register_obligation("A");
427+
forest.register_obligation("B");
428+
429+
let Outcome { completed: ok, errors: err, .. } =
430+
forest.process_obligations(&mut C(|obligation| {
431+
match *obligation {
432+
"A" => Err("An error"),
433+
"B" => Ok(Some(vec!["A"])),
434+
_ => unreachable!(),
435+
}
436+
}, |_|{}));
437+
assert_eq!(ok.len(), 0);
438+
assert_eq!(err, vec![super::Error {
439+
error: "An error",
440+
backtrace: vec!["A"]
441+
}]);
442+
443+
let mut forest = ObligationForest::new();
444+
forest.register_obligation("B");
445+
forest.register_obligation("A");
446+
447+
let Outcome { completed: ok, errors: err, .. } =
448+
forest.process_obligations(&mut C(|obligation| {
449+
match *obligation {
450+
"A" => Err("An error"),
451+
"B" => Ok(Some(vec!["A"])),
452+
_ => unreachable!(),
453+
}
454+
}, |_|{}));
455+
assert_eq!(ok.len(), 0);
456+
assert_eq!(err, vec![super::Error {
457+
error: "An error",
458+
backtrace: vec!["A"]
459+
}]);
460+
}

src/test/run-pass/issue-34503.rs

+20
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,20 @@
1+
// Copyright 2016 The Rust Project Developers. See the COPYRIGHT
2+
// file at the top-level directory of this distribution and at
3+
// http://rust-lang.org/COPYRIGHT.
4+
//
5+
// Licensed under the Apache License, Version 2.0 <LICENSE-APACHE or
6+
// http://www.apache.org/licenses/LICENSE-2.0> or the MIT license
7+
// <LICENSE-MIT or http://opensource.org/licenses/MIT>, at your
8+
// option. This file may not be copied, modified, or distributed
9+
// except according to those terms.
10+
11+
fn main() {
12+
struct X;
13+
trait Foo<T> {
14+
fn foo(&self) where (T, Option<T>): Ord {}
15+
fn bar(&self, x: &Option<T>) -> bool
16+
where Option<T>: Ord { *x < *x }
17+
}
18+
impl Foo<X> for () {}
19+
let _ = &() as &Foo<X>;
20+
}

0 commit comments

Comments
 (0)