Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Rollup of 8 pull requests #136507

Merged
merged 25 commits into from
Feb 4, 2025
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
25 commits
Select commit Hold shift + click to select a range
6054a33
split polonius context into per-phase data
lqd Jan 30, 2025
a8fc140
create context for errors and diagnostics for last borrowck phase
lqd Jan 30, 2025
6ce46a8
record boring locals in polonius context
lqd Jan 30, 2025
bb1385c
merge duplicate issue-46589 tests
lqd Jan 30, 2025
e2d1641
add explicit revisions to check-pass tests
lqd Jan 30, 2025
18d417f
add explicit revisions to polonius tests
lqd Jan 30, 2025
a616fa5
update NLL `get_default` test for poloniuses
lqd Jan 31, 2025
5f447a1
Add test of fn pointer without argument name
dtolnay Feb 1, 2025
b866deb
Omit argument names from function pointers that do not have argument …
dtolnay Feb 1, 2025
623d6e8
Notes on types/traits used for in-memory query caching
Zalathar Feb 3, 2025
f8b01b3
OnceCell & OnceLock docs: Using (un)initialized consistently
Pyr0de Feb 3, 2025
6e0dfc8
Refactor using the type-level constant value `ty::Value`
FedericoBruzzone Feb 2, 2025
190a8a6
tests: remove redundant `//@ ignore-{wasm,wasm32,emscripten}`
jieyouxu Feb 3, 2025
f6c1c57
platform-support docs: fix x87 errata footnotes
RalfJung Jan 27, 2025
e9b2349
Update books
rustbot Feb 3, 2025
00c61a8
Move `try_to_raw_bytes` from `ty::Valtree` to `ty::Value`
FedericoBruzzone Feb 3, 2025
56725e8
platform-support: document CPU baseline for x86-32 targets
RalfJung Feb 3, 2025
f2b7a29
Rollup merge of #136289 - Pyr0de:oncecell-docs, r=tgross35
matthiaskrgr Feb 3, 2025
e38f115
Rollup merge of #136299 - lqd:polonius-next-episode-9, r=jackh726
matthiaskrgr Feb 3, 2025
2c6c7f8
Rollup merge of #136411 - dtolnay:fnptr, r=notriddle
matthiaskrgr Feb 3, 2025
7e0118c
Rollup merge of #136430 - FedericoBruzzone:follow-up-136180, r=oli-obk
matthiaskrgr Feb 3, 2025
f180013
Rollup merge of #136476 - jieyouxu:panic-panic-panic, r=lcnr
matthiaskrgr Feb 3, 2025
d6f94a6
Rollup merge of #136484 - Zalathar:query-cache-notes, r=jieyouxu
matthiaskrgr Feb 3, 2025
628ae40
Rollup merge of #136493 - RalfJung:x86-platform-support, r=Noratrieb
matthiaskrgr Feb 3, 2025
1869633
Rollup merge of #136498 - rustbot:docs-update, r=ehuss
matthiaskrgr Feb 3, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
23 changes: 21 additions & 2 deletions compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs
Original file line number Diff line number Diff line change
Expand Up @@ -622,8 +622,25 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
}
}

// NLL doesn't consider boring locals for liveness, and wouldn't encounter a
// `Cause::LiveVar` for such a local. Polonius can't avoid computing liveness for boring
// locals yet, and will encounter them when trying to explain why a borrow contains a given
// point.
//
// We want to focus on relevant live locals in diagnostics, so when polonius is enabled, we
// ensure that we don't emit live boring locals as explanations.
let is_local_boring = |local| {
if let Some(polonius_diagnostics) = self.polonius_diagnostics {
polonius_diagnostics.boring_nll_locals.contains(&local)
} else {
assert!(!tcx.sess.opts.unstable_opts.polonius.is_next_enabled());

// Boring locals are never the cause of a borrow explanation in NLLs.
false
}
};
match find_use::find(body, regioncx, tcx, region_sub, use_location) {
Some(Cause::LiveVar(local, location)) => {
Some(Cause::LiveVar(local, location)) if !is_local_boring(local) => {
let span = body.source_info(location).span;
let spans = self
.move_spans(Place::from(local).as_ref(), location)
Expand Down Expand Up @@ -666,7 +683,9 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
}
}

None => {
Some(Cause::LiveVar(..)) | None => {
// Here, under NLL: no cause was found. Under polonius: no cause was found, or a
// boring local was found, which we ignore like NLLs do to match its diagnostics.
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
let (category, from_closure, span, region_name, path) =
self.free_region_constraint_info(borrow_region_vid, region);
Expand Down
10 changes: 8 additions & 2 deletions compiler/rustc_borrowck/src/lib.rs
Original file line number Diff line number Diff line change
Expand Up @@ -60,6 +60,7 @@ use crate::diagnostics::{
use crate::path_utils::*;
use crate::place_ext::PlaceExt;
use crate::places_conflict::{PlaceConflictBias, places_conflict};
use crate::polonius::PoloniusDiagnosticsContext;
use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
use crate::prefixes::PrefixSet;
use crate::region_infer::RegionInferenceContext;
Expand Down Expand Up @@ -198,7 +199,7 @@ fn do_mir_borrowck<'tcx>(
polonius_output,
opt_closure_req,
nll_errors,
localized_outlives_constraints,
polonius_diagnostics,
} = nll::compute_regions(
&infcx,
free_regions,
Expand Down Expand Up @@ -270,6 +271,7 @@ fn do_mir_borrowck<'tcx>(
polonius_output: None,
move_errors: Vec::new(),
diags_buffer,
polonius_diagnostics: polonius_diagnostics.as_ref(),
};
struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
Expand Down Expand Up @@ -308,6 +310,7 @@ fn do_mir_borrowck<'tcx>(
polonius_output,
move_errors: Vec::new(),
diags_buffer,
polonius_diagnostics: polonius_diagnostics.as_ref(),
};

// Compute and report region errors, if any.
Expand All @@ -329,7 +332,7 @@ fn do_mir_borrowck<'tcx>(
body,
&regioncx,
&borrow_set,
localized_outlives_constraints,
polonius_diagnostics.as_ref(),
&opt_closure_req,
);

Expand Down Expand Up @@ -579,6 +582,9 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> {

diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
move_errors: Vec<MoveError<'tcx>>,

/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
}

// Check that:
Expand Down
11 changes: 6 additions & 5 deletions compiler/rustc_borrowck/src/nll.rs
Original file line number Diff line number Diff line change
Expand Up @@ -27,7 +27,7 @@ use tracing::{debug, instrument};
use crate::borrow_set::BorrowSet;
use crate::consumers::ConsumerOptions;
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
use crate::polonius::LocalizedOutlivesConstraintSet;
use crate::polonius::PoloniusDiagnosticsContext;
use crate::polonius::legacy::{
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
};
Expand All @@ -46,8 +46,9 @@ pub(crate) struct NllOutput<'tcx> {
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
pub nll_errors: RegionErrors<'tcx>,

/// When using `-Zpolonius=next`: the localized typeck and liveness constraints.
pub localized_outlives_constraints: Option<LocalizedOutlivesConstraintSet>,
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics, e.g.
/// localized typeck and liveness constraints.
pub polonius_diagnostics: Option<PoloniusDiagnosticsContext>,
}

/// Rewrites the regions in the MIR to use NLL variables, also scraping out the set of universal
Expand Down Expand Up @@ -144,7 +145,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(

// If requested for `-Zpolonius=next`, convert NLL constraints to localized outlives constraints
// and use them to compute loan liveness.
let localized_outlives_constraints = polonius_context.as_ref().map(|polonius_context| {
let polonius_diagnostics = polonius_context.map(|polonius_context| {
polonius_context.compute_loan_liveness(infcx.tcx, &mut regioncx, body, borrow_set)
});

Expand Down Expand Up @@ -188,7 +189,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
polonius_output,
opt_closure_req: closure_region_requirements,
nll_errors,
localized_outlives_constraints,
polonius_diagnostics,
}
}

Expand Down
14 changes: 8 additions & 6 deletions compiler/rustc_borrowck/src/polonius/dump.rs
Original file line number Diff line number Diff line change
Expand Up @@ -12,7 +12,9 @@ use rustc_session::config::MirIncludeSpans;

use crate::borrow_set::BorrowSet;
use crate::constraints::OutlivesConstraint;
use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
use crate::polonius::{
LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet, PoloniusDiagnosticsContext,
};
use crate::region_infer::values::LivenessValues;
use crate::type_check::Locations;
use crate::{BorrowckInferCtxt, RegionInferenceContext};
Expand All @@ -23,7 +25,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
borrow_set: &BorrowSet<'tcx>,
localized_outlives_constraints: Option<LocalizedOutlivesConstraintSet>,
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
) {
let tcx = infcx.tcx;
Expand All @@ -35,8 +37,8 @@ pub(crate) fn dump_polonius_mir<'tcx>(
return;
}

let localized_outlives_constraints = localized_outlives_constraints
.expect("missing localized constraints with `-Zpolonius=next`");
let polonius_diagnostics =
polonius_diagnostics.expect("missing diagnostics context with `-Zpolonius=next`");

let _: io::Result<()> = try {
let mut file = create_dump_file(tcx, "html", false, "polonius", &0, body)?;
Expand All @@ -45,7 +47,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
body,
regioncx,
borrow_set,
localized_outlives_constraints,
&polonius_diagnostics.localized_outlives_constraints,
closure_region_requirements,
&mut file,
)?;
Expand All @@ -63,7 +65,7 @@ fn emit_polonius_dump<'tcx>(
body: &Body<'tcx>,
regioncx: &RegionInferenceContext<'tcx>,
borrow_set: &BorrowSet<'tcx>,
localized_outlives_constraints: LocalizedOutlivesConstraintSet,
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
out: &mut dyn io::Write,
) -> io::Result<()> {
Expand Down
24 changes: 2 additions & 22 deletions compiler/rustc_borrowck/src/polonius/liveness_constraints.rs
Original file line number Diff line number Diff line change
@@ -1,20 +1,19 @@
use std::collections::BTreeMap;

use rustc_index::bit_set::SparseBitMatrix;
use rustc_index::interval::SparseIntervalMatrix;
use rustc_middle::mir::{Body, Location};
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
use rustc_mir_dataflow::points::PointIndex;

use super::{
ConstraintDirection, LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet,
PoloniusContext,
PoloniusLivenessContext,
};
use crate::region_infer::values::LivenessValues;
use crate::universal_regions::UniversalRegions;

impl PoloniusContext {
impl PoloniusLivenessContext {
/// Record the variance of each region contained within the given value.
pub(crate) fn record_live_region_variance<'tcx>(
&mut self,
Expand All @@ -30,25 +29,6 @@ impl PoloniusContext {
};
extractor.relate(value, value).expect("Can't have a type error relating to itself");
}

/// Unlike NLLs, in polonius we traverse the cfg to look for regions live across an edge, so we
/// need to transpose the "points where each region is live" matrix to a "live regions per point"
/// matrix.
// FIXME: avoid this conversion by always storing liveness data in this shape in the rest of
// borrowck.
pub(crate) fn record_live_regions_per_point(
&mut self,
num_regions: usize,
points_per_live_region: &SparseIntervalMatrix<RegionVid, PointIndex>,
) {
let mut live_regions_per_point = SparseBitMatrix::new(num_regions);
for region in points_per_live_region.rows() {
for point in points_per_live_region.row(region).unwrap().iter() {
live_regions_per_point.insert(point, region);
}
}
self.live_regions = Some(live_regions_per_point);
}
}

/// Propagate loans throughout the CFG: for each statement in the MIR, create localized outlives
Expand Down
87 changes: 71 additions & 16 deletions compiler/rustc_borrowck/src/polonius/mod.rs
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,16 @@
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/22/polonius-part-1/>
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/29/polonius-part-2/>
//!
//!
//! Data flows like this:
//! 1) during MIR typeck, record liveness data needed later: live region variances, as well as the
//! usual NLL liveness data (just computed on more locals). That's the [PoloniusLivenessContext].
//! 2) once that is done, variance data is transferred, and the NLL region liveness is converted to
//! the polonius shape. That's the main [PoloniusContext].
//! 3) during region inference, that data and the NLL outlives constraints are used to create the
//! localized outlives constraints, as described above. That's the [PoloniusDiagnosticsContext].
//! 4) transfer this back to the main borrowck procedure: it handles computing errors and
//! diagnostics, debugging and MIR dumping concerns.

mod constraints;
mod dump;
Expand All @@ -42,8 +52,10 @@ mod typeck_constraints;

use std::collections::BTreeMap;

use rustc_data_structures::fx::FxHashSet;
use rustc_index::bit_set::SparseBitMatrix;
use rustc_middle::mir::Body;
use rustc_index::interval::SparseIntervalMatrix;
use rustc_middle::mir::{Body, Local};
use rustc_middle::ty::{RegionVid, TyCtxt};
use rustc_mir_dataflow::points::PointIndex;

Expand All @@ -57,15 +69,40 @@ use crate::{BorrowSet, RegionInferenceContext};

pub(crate) type LiveLoans = SparseBitMatrix<PointIndex, BorrowIndex>;

/// This struct holds the data needed to create the Polonius localized constraints.
/// This struct holds the liveness data created during MIR typeck, and which will be used later in
/// the process, to compute the polonius localized constraints.
#[derive(Default)]
pub(crate) struct PoloniusLivenessContext {
/// The expected edge direction per live region: the kind of directed edge we'll create as
/// liveness constraints depends on the variance of types with respect to each contained region.
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,

/// The regions that outlive free regions are used to distinguish relevant live locals from
/// boring locals. A boring local is one whose type contains only such regions. Polonius
/// currently has more boring locals than NLLs so we record the latter to use in errors and
/// diagnostics, to focus on the locals we consider relevant and match NLL diagnostics.
pub(crate) boring_nll_locals: FxHashSet<Local>,
}

/// This struct holds the data needed to create the Polonius localized constraints. Its data is
/// transferred and converted from the [PoloniusLivenessContext] at the end of MIR typeck.
pub(crate) struct PoloniusContext {
/// The liveness data we recorded during MIR typeck.
liveness_context: PoloniusLivenessContext,

/// The set of regions that are live at a given point in the CFG, used to create localized
/// outlives constraints between regions that are live at connected points in the CFG.
live_regions: Option<SparseBitMatrix<PointIndex, RegionVid>>,
live_regions: SparseBitMatrix<PointIndex, RegionVid>,
}

/// The expected edge direction per live region: the kind of directed edge we'll create as
/// liveness constraints depends on the variance of types with respect to each contained region.
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
/// This struct holds the data needed by the borrowck error computation and diagnostics. Its data is
/// computed from the [PoloniusContext] when computing NLL regions.
pub(crate) struct PoloniusDiagnosticsContext {
/// The localized outlives constraints that were computed in the main analysis.
localized_outlives_constraints: LocalizedOutlivesConstraintSet,

/// The liveness data computed during MIR typeck: [PoloniusLivenessContext::boring_nll_locals].
pub(crate) boring_nll_locals: FxHashSet<Local>,
}

/// The direction a constraint can flow into. Used to create liveness constraints according to
Expand All @@ -83,8 +120,24 @@ enum ConstraintDirection {
}

impl PoloniusContext {
pub(crate) fn new() -> PoloniusContext {
Self { live_region_variances: BTreeMap::new(), live_regions: None }
/// Unlike NLLs, in polonius we traverse the cfg to look for regions live across an edge, so we
/// need to transpose the "points where each region is live" matrix to a "live regions per point"
/// matrix.
// FIXME: avoid this conversion by always storing liveness data in this shape in the rest of
// borrowck.
pub(crate) fn create_from_liveness(
liveness_context: PoloniusLivenessContext,
num_regions: usize,
points_per_live_region: &SparseIntervalMatrix<RegionVid, PointIndex>,
) -> PoloniusContext {
let mut live_regions_per_point = SparseBitMatrix::new(num_regions);
for region in points_per_live_region.rows() {
for point in points_per_live_region.row(region).unwrap().iter() {
live_regions_per_point.insert(point, region);
}
}

PoloniusContext { live_regions: live_regions_per_point, liveness_context }
}

/// Computes live loans using the set of loans model for `-Zpolonius=next`.
Expand All @@ -95,13 +148,18 @@ impl PoloniusContext {
///
/// Then, this graph is traversed, and combined with kills, reachability is recorded as loan
/// liveness, to be used by the loan scope and active loans computations.
///
/// The constraint data will be used to compute errors and diagnostics.
pub(crate) fn compute_loan_liveness<'tcx>(
&self,
self,
tcx: TyCtxt<'tcx>,
regioncx: &mut RegionInferenceContext<'tcx>,
body: &Body<'tcx>,
borrow_set: &BorrowSet<'tcx>,
) -> LocalizedOutlivesConstraintSet {
) -> PoloniusDiagnosticsContext {
let PoloniusLivenessContext { live_region_variances, boring_nll_locals } =
self.liveness_context;

let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet::default();
convert_typeck_constraints(
tcx,
Expand All @@ -112,14 +170,11 @@ impl PoloniusContext {
&mut localized_outlives_constraints,
);

let live_regions = self.live_regions.as_ref().expect(
"live regions per-point data should have been created at the end of MIR typeck",
);
create_liveness_constraints(
body,
regioncx.liveness_constraints(),
live_regions,
&self.live_region_variances,
&self.live_regions,
&live_region_variances,
regioncx.universal_regions(),
&mut localized_outlives_constraints,
);
Expand All @@ -136,6 +191,6 @@ impl PoloniusContext {
);
regioncx.record_live_loans(live_loans);

localized_outlives_constraints
PoloniusDiagnosticsContext { localized_outlives_constraints, boring_nll_locals }
}
}
Loading
Loading