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 22, 2023
2 parents 5a9e0e8 + 952ab19 commit 08b2c37
Show file tree
Hide file tree
Showing 6 changed files with 100 additions and 98 deletions.
37 changes: 16 additions & 21 deletions compiler/rustc_borrowck/src/nll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -182,26 +182,22 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
let elements = &Rc::new(RegionValueElements::new(body));

// Run the MIR type-checker.
let MirTypeckResults {
constraints,
universal_region_relations,
opaque_type_values,
live_loans,
} = type_check::type_check(
infcx,
param_env,
body,
promoted,
&universal_regions,
location_table,
borrow_set,
&mut all_facts,
flow_inits,
move_data,
elements,
upvars,
polonius_input,
);
let MirTypeckResults { constraints, universal_region_relations, opaque_type_values } =
type_check::type_check(
infcx,
param_env,
body,
promoted,
&universal_regions,
location_table,
borrow_set,
&mut all_facts,
flow_inits,
move_data,
elements,
upvars,
polonius_input,
);

if let Some(all_facts) = &mut all_facts {
let _prof_timer = infcx.tcx.prof.generic_activity("polonius_fact_generation");
Expand Down Expand Up @@ -279,7 +275,6 @@ pub(crate) fn compute_regions<'cx, 'tcx>(
type_tests,
liveness_constraints,
elements,
live_loans,
);

// Generate various additional constraints.
Expand Down
12 changes: 3 additions & 9 deletions compiler/rustc_borrowck/src/region_infer/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -7,7 +7,6 @@ use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::scc::Sccs;
use rustc_errors::Diagnostic;
use rustc_hir::def_id::CRATE_DEF_ID;
use rustc_index::bit_set::SparseBitMatrix;
use rustc_index::{IndexSlice, IndexVec};
use rustc_infer::infer::outlives::test_type_match;
use rustc_infer::infer::region_constraints::{GenericKind, VarInfos, VerifyBound, VerifyIfEq};
Expand All @@ -31,8 +30,8 @@ use crate::{
nll::PoloniusOutput,
region_infer::reverse_sccs::ReverseSccGraph,
region_infer::values::{
LivenessValues, PlaceholderIndices, PointIndex, RegionElement, RegionValueElements,
RegionValues, ToElementIndex,
LivenessValues, PlaceholderIndices, RegionElement, RegionValueElements, RegionValues,
ToElementIndex,
},
type_check::{free_region_relations::UniversalRegionRelations, Locations},
universal_regions::UniversalRegions,
Expand Down Expand Up @@ -120,9 +119,6 @@ pub struct RegionInferenceContext<'tcx> {
/// Information about how the universally quantified regions in
/// scope on this function relate to one another.
universal_region_relations: Frozen<UniversalRegionRelations<'tcx>>,

/// The set of loans that are live at a given point in the CFG, when using `-Zpolonius=next`.
live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
}

/// Each time that `apply_member_constraint` is successful, it appends
Expand Down Expand Up @@ -335,7 +331,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
type_tests: Vec<TypeTest<'tcx>>,
liveness_constraints: LivenessValues<RegionVid>,
elements: &Rc<RegionValueElements>,
live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
) -> Self {
debug!("universal_regions: {:#?}", universal_regions);
debug!("outlives constraints: {:#?}", outlives_constraints);
Expand Down Expand Up @@ -389,7 +384,6 @@ impl<'tcx> RegionInferenceContext<'tcx> {
type_tests,
universal_regions,
universal_region_relations,
live_loans,
};

result.init_free_and_bound_regions();
Expand Down Expand Up @@ -2325,7 +2319,7 @@ impl<'tcx> RegionInferenceContext<'tcx> {
/// Note: for now, the sets of live loans is only available when using `-Zpolonius=next`.
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, location: Location) -> bool {
let point = self.liveness_constraints.point_from_location(location);
self.live_loans.contains(point, loan_idx)
self.liveness_constraints.is_loan_live_at(loan_idx, point)
}
}

Expand Down
64 changes: 63 additions & 1 deletion compiler/rustc_borrowck/src/region_infer/values.rs
Original file line number Diff line number Diff line change
Expand Up @@ -11,6 +11,8 @@ use rustc_middle::ty::{self, RegionVid};
use std::fmt::Debug;
use std::rc::Rc;

use crate::dataflow::BorrowIndex;

/// Maps between a `Location` and a `PointIndex` (and vice versa).
pub(crate) struct RegionValueElements {
/// For each basic block, how many points are contained within?
Expand Down Expand Up @@ -120,16 +122,47 @@ pub(crate) enum RegionElement {
/// When we initially compute liveness, we use an interval matrix storing
/// liveness ranges for each region-vid.
pub(crate) struct LivenessValues<N: Idx> {
/// The map from locations to points.
elements: Rc<RegionValueElements>,

/// For each region: the points where it is live.
points: SparseIntervalMatrix<N, PointIndex>,

/// When using `-Zpolonius=next`, for each point: the loans flowing into the live regions at
/// that point.
pub(crate) loans: Option<LiveLoans<N>>,
}

/// Data used to compute the loans that are live at a given point in the CFG, when using
/// `-Zpolonius=next`.
pub(crate) struct LiveLoans<N: Idx> {
/// The set of loans that flow into a given region. When individual regions are marked as live
/// in the CFG, these inflowing loans are recorded as live.
pub(crate) inflowing_loans: SparseBitMatrix<N, BorrowIndex>,

/// The set of loans that are live at a given point in the CFG.
pub(crate) live_loans: SparseBitMatrix<PointIndex, BorrowIndex>,
}

impl<N: Idx> LiveLoans<N> {
pub(crate) fn new(num_loans: usize) -> Self {
LiveLoans {
live_loans: SparseBitMatrix::new(num_loans),
inflowing_loans: SparseBitMatrix::new(num_loans),
}
}
}

impl<N: Idx> LivenessValues<N> {
/// Creates a new set of "region values" that tracks causal information.
/// Each of the regions in num_region_variables will be initialized with an
/// empty set of points and no causal information.
pub(crate) fn new(elements: Rc<RegionValueElements>) -> Self {
Self { points: SparseIntervalMatrix::new(elements.num_points), elements }
LivenessValues {
points: SparseIntervalMatrix::new(elements.num_points),
elements,
loans: None,
}
}

/// Iterate through each region that has a value in this set.
Expand All @@ -142,13 +175,33 @@ impl<N: Idx> LivenessValues<N> {
pub(crate) fn add_element(&mut self, row: N, location: Location) -> bool {
debug!("LivenessValues::add(r={:?}, location={:?})", row, location);
let index = self.elements.point_from_location(location);

// When available, record the loans flowing into this region as live at the given point.
if let Some(loans) = self.loans.as_mut() {
if let Some(inflowing) = loans.inflowing_loans.row(row) {
loans.live_loans.union_row(index, inflowing);
}
}

self.points.insert(row, index)
}

/// Adds all the elements in the given bit array into the given
/// region. Returns whether any of them are newly added.
pub(crate) fn add_elements(&mut self, row: N, locations: &IntervalSet<PointIndex>) -> bool {
debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations);

// When available, record the loans flowing into this region as live at the given points.
if let Some(loans) = self.loans.as_mut() {
if let Some(inflowing) = loans.inflowing_loans.row(row) {
if !inflowing.is_empty() {
for point in locations.iter() {
loans.live_loans.union_row(point, inflowing);
}
}
}
}

self.points.union_row(row, locations)
}

Expand Down Expand Up @@ -182,6 +235,15 @@ impl<N: Idx> LivenessValues<N> {
pub(crate) fn point_from_location(&self, location: Location) -> PointIndex {
self.elements.point_from_location(location)
}

/// When using `-Zpolonius=next`, returns whether the `loan_idx` is live at the given `point`.
pub(crate) fn is_loan_live_at(&self, loan_idx: BorrowIndex, point: PointIndex) -> bool {
self.loans
.as_ref()
.expect("Accessing live loans requires `-Zpolonius=next`")
.live_loans
.contains(point, loan_idx)
}
}

/// Maps from `ty::PlaceholderRegion` values that are used in the rest of
Expand Down
67 changes: 16 additions & 51 deletions compiler/rustc_borrowck/src/type_check/liveness/trace.rs
Original file line number Diff line number Diff line change
@@ -1,12 +1,12 @@
use rustc_data_structures::fx::{FxIndexMap, FxIndexSet};
use rustc_data_structures::graph::WithSuccessors;
use rustc_index::bit_set::{HybridBitSet, SparseBitMatrix};
use rustc_index::bit_set::HybridBitSet;
use rustc_index::interval::IntervalSet;
use rustc_infer::infer::canonical::QueryRegionConstraints;
use rustc_infer::infer::outlives::for_liveness;
use rustc_middle::mir::{BasicBlock, Body, ConstraintCategory, Local, Location};
use rustc_middle::traits::query::DropckOutlivesResult;
use rustc_middle::ty::{RegionVid, Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
use rustc_middle::ty::{Ty, TyCtxt, TypeVisitable, TypeVisitableExt};
use rustc_span::DUMMY_SP;
use rustc_trait_selection::traits::query::type_op::outlives::DropckOutlives;
use rustc_trait_selection::traits::query::type_op::{TypeOp, TypeOpOutput};
Expand All @@ -16,9 +16,8 @@ use rustc_mir_dataflow::impls::MaybeInitializedPlaces;
use rustc_mir_dataflow::move_paths::{HasMoveData, MoveData, MovePathIndex};
use rustc_mir_dataflow::ResultsCursor;

use crate::dataflow::BorrowIndex;
use crate::{
region_infer::values::{self, PointIndex, RegionValueElements},
region_infer::values::{self, LiveLoans, PointIndex, RegionValueElements},
type_check::liveness::local_use_map::LocalUseMap,
type_check::liveness::polonius,
type_check::NormalizeLocation,
Expand Down Expand Up @@ -54,17 +53,17 @@ pub(super) fn trace<'mir, 'tcx>(
let local_use_map = &LocalUseMap::build(&relevant_live_locals, elements, body);

// When using `-Zpolonius=next`, compute the set of loans that can reach a given region.
let num_loans = typeck.borrowck_context.borrow_set.len();
let mut inflowing_loans = SparseBitMatrix::new(num_loans);
if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() {
let borrowck_context = &typeck.borrowck_context;
let borrowck_context = &mut typeck.borrowck_context;

let borrow_set = &borrowck_context.borrow_set;
let constraint_set = &borrowck_context.constraints.outlives_constraints;
let mut live_loans = LiveLoans::new(borrow_set.len());

let num_region_vars = typeck.infcx.num_region_vars();
let graph = constraint_set.graph(num_region_vars);
let outlives_constraints = &borrowck_context.constraints.outlives_constraints;
let graph = outlives_constraints.graph(num_region_vars);
let region_graph =
graph.region_graph(constraint_set, borrowck_context.universal_regions.fr_static);
graph.region_graph(outlives_constraints, borrowck_context.universal_regions.fr_static);

// Traverse each issuing region's constraints, and record the loan as flowing into the
// outlived region.
Expand All @@ -75,9 +74,13 @@ pub(super) fn trace<'mir, 'tcx>(
continue;
}

inflowing_loans.insert(succ, loan);
live_loans.inflowing_loans.insert(succ, loan);
}
}

// Store the inflowing loans in the liveness constraints: they will be used to compute live
// loans when liveness data is recorded there.
borrowck_context.constraints.liveness_constraints.loans = Some(live_loans);
};

let cx = LivenessContext {
Expand All @@ -88,7 +91,6 @@ pub(super) fn trace<'mir, 'tcx>(
local_use_map,
move_data,
drop_data: FxIndexMap::default(),
inflowing_loans,
};

let mut results = LivenessResults::new(cx);
Expand Down Expand Up @@ -126,9 +128,6 @@ struct LivenessContext<'me, 'typeck, 'flow, 'tcx> {
/// Index indicating where each variable is assigned, used, or
/// dropped.
local_use_map: &'me LocalUseMap,

/// Set of loans that flow into a given region, when using `-Zpolonius=next`.
inflowing_loans: SparseBitMatrix<RegionVid, BorrowIndex>,
}

struct DropData<'tcx> {
Expand Down Expand Up @@ -519,14 +518,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
live_at: &IntervalSet<PointIndex>,
) {
debug!("add_use_live_facts_for(value={:?})", value);

Self::make_all_regions_live(
self.elements,
self.typeck,
value,
live_at,
&self.inflowing_loans,
);
Self::make_all_regions_live(self.elements, self.typeck, value, live_at);
}

/// Some variable with type `live_ty` is "drop live" at `location`
Expand Down Expand Up @@ -577,14 +569,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
// All things in the `outlives` array may be touched by
// the destructor and must be live at this point.
for &kind in &drop_data.dropck_result.kinds {
Self::make_all_regions_live(
self.elements,
self.typeck,
kind,
live_at,
&self.inflowing_loans,
);

Self::make_all_regions_live(self.elements, self.typeck, kind, live_at);
polonius::add_drop_of_var_derefs_origin(self.typeck, dropped_local, &kind);
}
}
Expand All @@ -594,20 +579,13 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
typeck: &mut TypeChecker<'_, 'tcx>,
value: impl TypeVisitable<TyCtxt<'tcx>>,
live_at: &IntervalSet<PointIndex>,
inflowing_loans: &SparseBitMatrix<RegionVid, BorrowIndex>,
) {
debug!("make_all_regions_live(value={:?})", value);
debug!(
"make_all_regions_live: live_at={}",
values::location_set_str(elements, live_at.iter()),
);

// When using `-Zpolonius=next`, we want to record the loans that flow into this value's
// regions as being live at the given `live_at` points: this will be used to compute the
// location where a loan goes out of scope.
let num_loans = typeck.borrowck_context.borrow_set.len();
let value_loans = &mut HybridBitSet::new_empty(num_loans);

value.visit_with(&mut for_liveness::FreeRegionsVisitor {
tcx: typeck.tcx(),
param_env: typeck.param_env,
Expand All @@ -619,21 +597,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> {
.constraints
.liveness_constraints
.add_elements(live_region_vid, live_at);

// There can only be inflowing loans for this region when we are using
// `-Zpolonius=next`.
if let Some(inflowing) = inflowing_loans.row(live_region_vid) {
value_loans.union(inflowing);
}
},
});

// Record the loans reaching the value.
if !value_loans.is_empty() {
for point in live_at.iter() {
typeck.borrowck_context.live_loans.union_row(point, value_loans);
}
}
}

fn compute_drop_data(
Expand Down

0 comments on commit 08b2c37

Please sign in to comment.