Skip to content

Commit

Permalink
Auto merge of rust-lang#117593 - lqd:polonius-crater, r=<try>
Browse files Browse the repository at this point in the history
crater: assert_eq!(NLL, location-insensitive polonius);

Crater run to check `-Zpolonius=next`. Any differences in how NLLs and location-insensitive polonius compute scopes will cause an assert to trip and an ICE.

Depends on rust-lang#117560 to fix the last known fuzzing example where there was such a difference.

r? `@ghost`
  • Loading branch information
bors committed Nov 4, 2023
2 parents a42d94e + 16af7f5 commit 031b389
Show file tree
Hide file tree
Showing 6 changed files with 115 additions and 14 deletions.
6 changes: 3 additions & 3 deletions compiler/rustc_borrowck/src/dataflow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -273,11 +273,10 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
) {
let sccs = self.regioncx.constraint_sccs();
let universal_regions = self.regioncx.universal_regions();
let issuing_region_scc = sccs.scc(issuing_region);

// We first handle the cases where the loan doesn't go out of scope, depending on the issuing
// region's successors.
for scc in sccs.depth_first_search(issuing_region_scc) {
for successor in self.regioncx.region_graph().depth_first_search(issuing_region) {
// 1. Via applied member constraints
//
// The issuing region can flow into the choice regions, and they are either:
Expand All @@ -290,6 +289,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
// For additional insurance via fuzzing and crater, we verify that the constraint's min
// choice indeed escapes the function. In the future, we could e.g. turn this check into
// a debug assert and early return as an optimization.
let scc = sccs.scc(successor);
for constraint in self.regioncx.applied_member_constraints(scc) {
if universal_regions.is_universal_region(constraint.min_choice) {
return;
Expand All @@ -300,7 +300,7 @@ impl<'tcx> PoloniusOutOfScopePrecomputer<'_, 'tcx> {
//
// If the issuing region outlives such a region, its loan escapes the function and
// cannot go out of scope. We can early return.
if self.regioncx.scc_is_live_at_all_points(scc) {
if self.regioncx.is_region_live_at_all_points(successor) {
return;
}
}
Expand Down
21 changes: 11 additions & 10 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -22,11 +22,10 @@ use rustc_middle::traits::ObligationCauseCode;
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeFoldable, TypeVisitableExt};
use rustc_span::Span;

use crate::constraints::graph::{self, NormalConstraintGraph, RegionGraph};
use crate::dataflow::BorrowIndex;
use crate::{
constraints::{
graph::NormalConstraintGraph, ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet,
},
constraints::{ConstraintSccIndex, OutlivesConstraint, OutlivesConstraintSet},
diagnostics::{RegionErrorKind, RegionErrors, UniverseInfo},
member_constraints::{MemberConstraintSet, NllMemberConstraintIndex},
nll::PoloniusOutput,
Expand Down Expand Up @@ -2293,19 +2292,21 @@ impl<'tcx> RegionInferenceContext<'tcx> {
self.constraint_sccs.as_ref()
}

/// Returns whether the given SCC is live at all points: whether the representative is a
/// Access to the region graph, built from the outlives constraints.
pub(crate) fn region_graph(&self) -> RegionGraph<'_, 'tcx, graph::Normal> {
self.constraint_graph.region_graph(&self.constraints, self.universal_regions.fr_static)
}

/// Returns whether the given region is considered live at all points: whether it is a
/// placeholder or a free region.
pub(crate) fn scc_is_live_at_all_points(&self, scc: ConstraintSccIndex) -> bool {
pub(crate) fn is_region_live_at_all_points(&self, region: RegionVid) -> bool {
// FIXME: there must be a cleaner way to find this information. At least, when
// higher-ranked subtyping is abstracted away from the borrowck main path, we'll only
// need to check whether this is a universal region.
let representative = self.scc_representatives[scc];
let origin = self.var_infos[representative].origin;
let origin = self.region_definition(region).origin;
let live_at_all_points = matches!(
origin,
RegionVariableOrigin::Nll(
NllRegionVariableOrigin::Placeholder(_) | NllRegionVariableOrigin::FreeRegion
)
NllRegionVariableOrigin::Placeholder(_) | NllRegionVariableOrigin::FreeRegion
);
live_at_all_points
}
Expand Down
2 changes: 1 addition & 1 deletion compiler/rustc_session/src/config.rs
Original file line number Diff line number Diff line change
Expand Up @@ -3414,13 +3414,13 @@ impl DumpMonoStatsFormat {
#[derive(Clone, Copy, PartialEq, Hash, Debug, Default)]
pub enum Polonius {
/// The default value: disabled.
#[default]
Off,

/// Legacy version, using datalog and the `polonius-engine` crate. Historical value for `-Zpolonius`.
Legacy,

/// In-tree prototype, extending the NLL infrastructure.
#[default]
Next,
}

Expand Down
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
error[E0597]: `a` does not live long enough
--> $DIR/location-insensitive-scopes-issue-117146.rs:10:18
|
LL | let b = |_| &a;
| --- -^
| | ||
| | |borrowed value does not live long enough
| | returning this value requires that `a` is borrowed for `'static`
| value captured here
...
LL | }
| - `a` dropped here while still borrowed
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
--> $DIR/location-insensitive-scopes-issue-117146.rs:20:22
|
LL | fn bad<F: Fn(&()) -> &()>(_: F) {}
| ^^^

error: implementation of `Fn` is not general enough
--> $DIR/location-insensitive-scopes-issue-117146.rs:13:5
|
LL | bad(&b);
| ^^^^^^^ implementation of `Fn` is not general enough
|
= note: closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`...
= note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2`

error: implementation of `FnOnce` is not general enough
--> $DIR/location-insensitive-scopes-issue-117146.rs:13:5
|
LL | bad(&b);
| ^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0597`.
Original file line number Diff line number Diff line change
@@ -0,0 +1,40 @@
error[E0597]: `a` does not live long enough
--> $DIR/location-insensitive-scopes-issue-117146.rs:10:18
|
LL | let b = |_| &a;
| --- -^
| | ||
| | |borrowed value does not live long enough
| | returning this value requires that `a` is borrowed for `'static`
| value captured here
...
LL | }
| - `a` dropped here while still borrowed
|
note: due to current limitations in the borrow checker, this implies a `'static` lifetime
--> $DIR/location-insensitive-scopes-issue-117146.rs:20:22
|
LL | fn bad<F: Fn(&()) -> &()>(_: F) {}
| ^^^

error: implementation of `Fn` is not general enough
--> $DIR/location-insensitive-scopes-issue-117146.rs:13:5
|
LL | bad(&b);
| ^^^^^^^ implementation of `Fn` is not general enough
|
= note: closure with signature `fn(&'2 ()) -> &()` must implement `Fn<(&'1 (),)>`, for any lifetime `'1`...
= note: ...but it actually implements `Fn<(&'2 (),)>`, for some specific lifetime `'2`

error: implementation of `FnOnce` is not general enough
--> $DIR/location-insensitive-scopes-issue-117146.rs:13:5
|
LL | bad(&b);
| ^^^^^^^ implementation of `FnOnce` is not general enough
|
= note: closure with signature `fn(&'2 ()) -> &()` must implement `FnOnce<(&'1 (),)>`, for any lifetime `'1`...
= note: ...but it actually implements `FnOnce<(&'2 (),)>`, for some specific lifetime `'2`

error: aborting due to 3 previous errors

For more information about this error, try `rustc --explain E0597`.
20 changes: 20 additions & 0 deletions tests/ui/nll/polonius/location-insensitive-scopes-issue-117146.rs
Original file line number Diff line number Diff line change
@@ -0,0 +1,20 @@
// This is a non-regression test for issue #117146, where NLL and `-Zpolonius=next` computed
// different loan scopes when a region flowed into an SCC whose representative was an existential
// region.

// revisions: nll polonius
// [polonius] compile-flags: -Zpolonius=next

fn main() {
let a = ();
let b = |_| &a;
//[nll]~^ ERROR `a` does not live long enough
//[polonius]~^^ ERROR `a` does not live long enough
bad(&b);
//[nll]~^ ERROR implementation of `Fn`
//[nll]~| ERROR implementation of `FnOnce`
//[polonius]~^^^ ERROR implementation of `Fn`
//[polonius]~| ERROR implementation of `FnOnce`
}

fn bad<F: Fn(&()) -> &()>(_: F) {}

0 comments on commit 031b389

Please sign in to comment.