Skip to content

Commit fced2b1

Browse files
committed
fix SCCs containing mixture of universes
And add a test showing a universe violation getting caught.
1 parent f0e3a09 commit fced2b1

File tree

3 files changed

+61
-28
lines changed

3 files changed

+61
-28
lines changed

src/librustc_mir/borrow_check/nll/region_infer/mod.rs

Lines changed: 30 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -319,23 +319,34 @@ impl<'tcx> RegionInferenceContext<'tcx> {
319319
}
320320

321321
for variable in self.definitions.indices() {
322+
let scc = self.constraint_sccs.scc(variable);
323+
322324
match self.definitions[variable].origin {
323325
NLLRegionVariableOrigin::FreeRegion => {
324326
// For each free, universally quantified region X:
325327

326328
// Add all nodes in the CFG to liveness constraints
327-
let variable_scc = self.constraint_sccs.scc(variable);
328329
self.liveness_constraints.add_all_points(variable);
329-
self.scc_values.add_all_points(variable_scc);
330+
self.scc_values.add_all_points(scc);
330331

331332
// Add `end(X)` into the set for X.
332-
self.add_element_to_scc_of(variable, variable);
333+
self.scc_values.add_element(scc, variable);
333334
}
334335

335336
NLLRegionVariableOrigin::BoundRegion(ui) => {
336337
// Each placeholder region X outlives its
337-
// associated universe but nothing else.
338-
self.add_element_to_scc_of(variable, ui);
338+
// associated universe but nothing else. Every
339+
// placeholder region is always in a universe that
340+
// contains `ui` -- but when placeholder regions
341+
// are placed into an SCC, that SCC may include
342+
// things from other universes that do not include
343+
// `ui`.
344+
let scc_universe = self.scc_universes[scc];
345+
if ui.is_subset_of(scc_universe) {
346+
self.scc_values.add_element(scc, ui);
347+
} else {
348+
self.add_incompatible_universe(scc);
349+
}
339350
}
340351

341352
NLLRegionVariableOrigin::Existential => {
@@ -383,13 +394,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
383394
self.scc_universes[scc]
384395
}
385396

386-
/// Adds `elem` to the value of the SCC in which `v` appears.
387-
fn add_element_to_scc_of(&mut self, v: RegionVid, elem: impl ToElementIndex) {
388-
debug!("add_live_element({:?}, {:?})", v, elem);
389-
let scc = self.constraint_sccs.scc(v);
390-
self.scc_values.add_element(scc, elem);
391-
}
392-
393397
/// Perform region inference and report errors if we see any
394398
/// unsatisfiable constraints. If this is a closure, returns the
395399
/// region requirements to propagate to our creator, if any.
@@ -516,22 +520,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
516520
// merge the bits.
517521
self.scc_values.add_region(scc_a, scc_b);
518522
} else {
519-
// Otherwise, the only way for `A` to outlive `B`
520-
// is for it to outlive static. This is actually stricter
521-
// than necessary: ideally, we'd support bounds like `for<'a: 'b`>`
522-
// that might then allow us to approximate `'a` with `'b` and not
523-
// `'static`. But it will have to do for now.
524-
//
525-
// The code here is a bit hacky: we grab the current
526-
// value of the SCC in which `'static` appears, but
527-
// this value may not be fully computed yet. That's ok
528-
// though: it will contain the base liveness values,
529-
// which include (a) the static free region element
530-
// and (b) all the points in the CFG, so it is "good
531-
// enough" to bring it in here for our purposes.
532-
let fr_static = self.universal_regions.fr_static;
533-
let scc_static = constraint_sccs.scc(fr_static);
534-
self.scc_values.add_region(scc_a, scc_static);
523+
self.add_incompatible_universe(scc_a);
535524
}
536525
}
537526

@@ -563,6 +552,19 @@ impl<'tcx> RegionInferenceContext<'tcx> {
563552
.all(|u| u.is_subset_of(universe_a))
564553
}
565554

555+
/// Extend `scc` so that it can outlive some placeholder region
556+
/// from a universe it can't name; at present, the only way for
557+
/// this to be true is if `scc` outlives `'static`. This is
558+
/// actually stricter than necessary: ideally, we'd support bounds
559+
/// like `for<'a: 'b`>` that might then allow us to approximate
560+
/// `'a` with `'b` and not `'static`. But it will have to do for
561+
/// now.
562+
fn add_incompatible_universe(&mut self, scc: ConstraintSccIndex) {
563+
let fr_static = self.universal_regions.fr_static;
564+
self.scc_values.add_all_points(scc);
565+
self.scc_values.add_element(scc, fr_static);
566+
}
567+
566568
/// Once regions have been propagated, this method is used to see
567569
/// whether the "type tests" produced by typeck were satisfied;
568570
/// type tests encode type-outlives relationships like `T:
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
// Test that the NLL `relate_tys` code correctly deduces that a
2+
// function returning either argument CANNOT be upcast to one
3+
// that returns always its first argument.
4+
//
5+
// compile-flags:-Zno-leak-check
6+
7+
#![feature(nll)]
8+
9+
fn make_it() -> fn(&'static u32) -> &'static u32 {
10+
panic!()
11+
}
12+
13+
fn main() {
14+
let a: fn(_) -> _ = make_it();
15+
let b: fn(&u32) -> &u32 = a;
16+
drop(a);
17+
}
Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,14 @@
1+
error: higher-ranked subtype error
2+
--> $DIR/universe-violation.rs:14:9
3+
|
4+
LL | let a: fn(_) -> _ = make_it();
5+
| ^
6+
7+
error: higher-ranked subtype error
8+
--> $DIR/universe-violation.rs:15:9
9+
|
10+
LL | let b: fn(&u32) -> &u32 = a;
11+
| ^
12+
13+
error: aborting due to 2 previous errors
14+

0 commit comments

Comments
 (0)