Skip to content

Commit c705b7d

Browse files
committed
Auto merge of #136507 - matthiaskrgr:rollup-uzwv9mo, r=matthiaskrgr
Rollup of 8 pull requests Successful merges: - #136289 (OnceCell & OnceLock docs: Using (un)initialized consistently) - #136299 (Ignore NLL boring locals in polonius diagnostics) - #136411 (Omit argument names from function pointers that do not have argument names) - #136430 (Use the type-level constant value `ty::Value` where needed) - #136476 (Remove generic `//@ ignore-{wasm,wasm32,emscripten}` in tests) - #136484 (Notes on types/traits used for in-memory query caching) - #136493 (platform-support: document CPU baseline for x86-32 targets) - #136498 (Update books) r? `@ghost` `@rustbot` modify labels: rollup
2 parents affdb59 + 1869633 commit c705b7d

File tree

69 files changed

+627
-345
lines changed

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

69 files changed

+627
-345
lines changed

compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs

+21-2
Original file line numberDiff line numberDiff line change
@@ -622,8 +622,25 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
622622
}
623623
}
624624

625+
// NLL doesn't consider boring locals for liveness, and wouldn't encounter a
626+
// `Cause::LiveVar` for such a local. Polonius can't avoid computing liveness for boring
627+
// locals yet, and will encounter them when trying to explain why a borrow contains a given
628+
// point.
629+
//
630+
// We want to focus on relevant live locals in diagnostics, so when polonius is enabled, we
631+
// ensure that we don't emit live boring locals as explanations.
632+
let is_local_boring = |local| {
633+
if let Some(polonius_diagnostics) = self.polonius_diagnostics {
634+
polonius_diagnostics.boring_nll_locals.contains(&local)
635+
} else {
636+
assert!(!tcx.sess.opts.unstable_opts.polonius.is_next_enabled());
637+
638+
// Boring locals are never the cause of a borrow explanation in NLLs.
639+
false
640+
}
641+
};
625642
match find_use::find(body, regioncx, tcx, region_sub, use_location) {
626-
Some(Cause::LiveVar(local, location)) => {
643+
Some(Cause::LiveVar(local, location)) if !is_local_boring(local) => {
627644
let span = body.source_info(location).span;
628645
let spans = self
629646
.move_spans(Place::from(local).as_ref(), location)
@@ -666,7 +683,9 @@ impl<'tcx> MirBorrowckCtxt<'_, '_, 'tcx> {
666683
}
667684
}
668685

669-
None => {
686+
Some(Cause::LiveVar(..)) | None => {
687+
// Here, under NLL: no cause was found. Under polonius: no cause was found, or a
688+
// boring local was found, which we ignore like NLLs do to match its diagnostics.
670689
if let Some(region) = self.to_error_region_vid(borrow_region_vid) {
671690
let (category, from_closure, span, region_name, path) =
672691
self.free_region_constraint_info(borrow_region_vid, region);

compiler/rustc_borrowck/src/lib.rs

+8-2
Original file line numberDiff line numberDiff line change
@@ -60,6 +60,7 @@ use crate::diagnostics::{
6060
use crate::path_utils::*;
6161
use crate::place_ext::PlaceExt;
6262
use crate::places_conflict::{PlaceConflictBias, places_conflict};
63+
use crate::polonius::PoloniusDiagnosticsContext;
6364
use crate::polonius::legacy::{PoloniusLocationTable, PoloniusOutput};
6465
use crate::prefixes::PrefixSet;
6566
use crate::region_infer::RegionInferenceContext;
@@ -198,7 +199,7 @@ fn do_mir_borrowck<'tcx>(
198199
polonius_output,
199200
opt_closure_req,
200201
nll_errors,
201-
localized_outlives_constraints,
202+
polonius_diagnostics,
202203
} = nll::compute_regions(
203204
&infcx,
204205
free_regions,
@@ -270,6 +271,7 @@ fn do_mir_borrowck<'tcx>(
270271
polonius_output: None,
271272
move_errors: Vec::new(),
272273
diags_buffer,
274+
polonius_diagnostics: polonius_diagnostics.as_ref(),
273275
};
274276
struct MoveVisitor<'a, 'b, 'infcx, 'tcx> {
275277
ctxt: &'a mut MirBorrowckCtxt<'b, 'infcx, 'tcx>,
@@ -308,6 +310,7 @@ fn do_mir_borrowck<'tcx>(
308310
polonius_output,
309311
move_errors: Vec::new(),
310312
diags_buffer,
313+
polonius_diagnostics: polonius_diagnostics.as_ref(),
311314
};
312315

313316
// Compute and report region errors, if any.
@@ -329,7 +332,7 @@ fn do_mir_borrowck<'tcx>(
329332
body,
330333
&regioncx,
331334
&borrow_set,
332-
localized_outlives_constraints,
335+
polonius_diagnostics.as_ref(),
333336
&opt_closure_req,
334337
);
335338

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

580583
diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>,
581584
move_errors: Vec<MoveError<'tcx>>,
585+
586+
/// When using `-Zpolonius=next`: the data used to compute errors and diagnostics.
587+
polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>,
582588
}
583589

584590
// Check that:

compiler/rustc_borrowck/src/nll.rs

+6-5
Original file line numberDiff line numberDiff line change
@@ -27,7 +27,7 @@ use tracing::{debug, instrument};
2727
use crate::borrow_set::BorrowSet;
2828
use crate::consumers::ConsumerOptions;
2929
use crate::diagnostics::{BorrowckDiagnosticsBuffer, RegionErrors};
30-
use crate::polonius::LocalizedOutlivesConstraintSet;
30+
use crate::polonius::PoloniusDiagnosticsContext;
3131
use crate::polonius::legacy::{
3232
PoloniusFacts, PoloniusFactsExt, PoloniusLocationTable, PoloniusOutput,
3333
};
@@ -46,8 +46,9 @@ pub(crate) struct NllOutput<'tcx> {
4646
pub opt_closure_req: Option<ClosureRegionRequirements<'tcx>>,
4747
pub nll_errors: RegionErrors<'tcx>,
4848

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

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

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

@@ -188,7 +189,7 @@ pub(crate) fn compute_regions<'a, 'tcx>(
188189
polonius_output,
189190
opt_closure_req: closure_region_requirements,
190191
nll_errors,
191-
localized_outlives_constraints,
192+
polonius_diagnostics,
192193
}
193194
}
194195

compiler/rustc_borrowck/src/polonius/dump.rs

+8-6
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,9 @@ use rustc_session::config::MirIncludeSpans;
1212

1313
use crate::borrow_set::BorrowSet;
1414
use crate::constraints::OutlivesConstraint;
15-
use crate::polonius::{LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet};
15+
use crate::polonius::{
16+
LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet, PoloniusDiagnosticsContext,
17+
};
1618
use crate::region_infer::values::LivenessValues;
1719
use crate::type_check::Locations;
1820
use crate::{BorrowckInferCtxt, RegionInferenceContext};
@@ -23,7 +25,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
2325
body: &Body<'tcx>,
2426
regioncx: &RegionInferenceContext<'tcx>,
2527
borrow_set: &BorrowSet<'tcx>,
26-
localized_outlives_constraints: Option<LocalizedOutlivesConstraintSet>,
28+
polonius_diagnostics: Option<&PoloniusDiagnosticsContext>,
2729
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
2830
) {
2931
let tcx = infcx.tcx;
@@ -35,8 +37,8 @@ pub(crate) fn dump_polonius_mir<'tcx>(
3537
return;
3638
}
3739

38-
let localized_outlives_constraints = localized_outlives_constraints
39-
.expect("missing localized constraints with `-Zpolonius=next`");
40+
let polonius_diagnostics =
41+
polonius_diagnostics.expect("missing diagnostics context with `-Zpolonius=next`");
4042

4143
let _: io::Result<()> = try {
4244
let mut file = create_dump_file(tcx, "html", false, "polonius", &0, body)?;
@@ -45,7 +47,7 @@ pub(crate) fn dump_polonius_mir<'tcx>(
4547
body,
4648
regioncx,
4749
borrow_set,
48-
localized_outlives_constraints,
50+
&polonius_diagnostics.localized_outlives_constraints,
4951
closure_region_requirements,
5052
&mut file,
5153
)?;
@@ -63,7 +65,7 @@ fn emit_polonius_dump<'tcx>(
6365
body: &Body<'tcx>,
6466
regioncx: &RegionInferenceContext<'tcx>,
6567
borrow_set: &BorrowSet<'tcx>,
66-
localized_outlives_constraints: LocalizedOutlivesConstraintSet,
68+
localized_outlives_constraints: &LocalizedOutlivesConstraintSet,
6769
closure_region_requirements: &Option<ClosureRegionRequirements<'tcx>>,
6870
out: &mut dyn io::Write,
6971
) -> io::Result<()> {

compiler/rustc_borrowck/src/polonius/liveness_constraints.rs

+2-22
Original file line numberDiff line numberDiff line change
@@ -1,20 +1,19 @@
11
use std::collections::BTreeMap;
22

33
use rustc_index::bit_set::SparseBitMatrix;
4-
use rustc_index::interval::SparseIntervalMatrix;
54
use rustc_middle::mir::{Body, Location};
65
use rustc_middle::ty::relate::{self, Relate, RelateResult, TypeRelation};
76
use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt, TypeVisitable};
87
use rustc_mir_dataflow::points::PointIndex;
98

109
use super::{
1110
ConstraintDirection, LocalizedOutlivesConstraint, LocalizedOutlivesConstraintSet,
12-
PoloniusContext,
11+
PoloniusLivenessContext,
1312
};
1413
use crate::region_infer::values::LivenessValues;
1514
use crate::universal_regions::UniversalRegions;
1615

17-
impl PoloniusContext {
16+
impl PoloniusLivenessContext {
1817
/// Record the variance of each region contained within the given value.
1918
pub(crate) fn record_live_region_variance<'tcx>(
2019
&mut self,
@@ -30,25 +29,6 @@ impl PoloniusContext {
3029
};
3130
extractor.relate(value, value).expect("Can't have a type error relating to itself");
3231
}
33-
34-
/// Unlike NLLs, in polonius we traverse the cfg to look for regions live across an edge, so we
35-
/// need to transpose the "points where each region is live" matrix to a "live regions per point"
36-
/// matrix.
37-
// FIXME: avoid this conversion by always storing liveness data in this shape in the rest of
38-
// borrowck.
39-
pub(crate) fn record_live_regions_per_point(
40-
&mut self,
41-
num_regions: usize,
42-
points_per_live_region: &SparseIntervalMatrix<RegionVid, PointIndex>,
43-
) {
44-
let mut live_regions_per_point = SparseBitMatrix::new(num_regions);
45-
for region in points_per_live_region.rows() {
46-
for point in points_per_live_region.row(region).unwrap().iter() {
47-
live_regions_per_point.insert(point, region);
48-
}
49-
}
50-
self.live_regions = Some(live_regions_per_point);
51-
}
5232
}
5333

5434
/// Propagate loans throughout the CFG: for each statement in the MIR, create localized outlives

compiler/rustc_borrowck/src/polonius/mod.rs

+71-16
Original file line numberDiff line numberDiff line change
@@ -32,6 +32,16 @@
3232
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/22/polonius-part-1/>
3333
//! - <https://smallcultfollowing.com/babysteps/blog/2023/09/29/polonius-part-2/>
3434
//!
35+
//!
36+
//! Data flows like this:
37+
//! 1) during MIR typeck, record liveness data needed later: live region variances, as well as the
38+
//! usual NLL liveness data (just computed on more locals). That's the [PoloniusLivenessContext].
39+
//! 2) once that is done, variance data is transferred, and the NLL region liveness is converted to
40+
//! the polonius shape. That's the main [PoloniusContext].
41+
//! 3) during region inference, that data and the NLL outlives constraints are used to create the
42+
//! localized outlives constraints, as described above. That's the [PoloniusDiagnosticsContext].
43+
//! 4) transfer this back to the main borrowck procedure: it handles computing errors and
44+
//! diagnostics, debugging and MIR dumping concerns.
3545
3646
mod constraints;
3747
mod dump;
@@ -42,8 +52,10 @@ mod typeck_constraints;
4252

4353
use std::collections::BTreeMap;
4454

55+
use rustc_data_structures::fx::FxHashSet;
4556
use rustc_index::bit_set::SparseBitMatrix;
46-
use rustc_middle::mir::Body;
57+
use rustc_index::interval::SparseIntervalMatrix;
58+
use rustc_middle::mir::{Body, Local};
4759
use rustc_middle::ty::{RegionVid, TyCtxt};
4860
use rustc_mir_dataflow::points::PointIndex;
4961

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

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

60-
/// This struct holds the data needed to create the Polonius localized constraints.
72+
/// This struct holds the liveness data created during MIR typeck, and which will be used later in
73+
/// the process, to compute the polonius localized constraints.
74+
#[derive(Default)]
75+
pub(crate) struct PoloniusLivenessContext {
76+
/// The expected edge direction per live region: the kind of directed edge we'll create as
77+
/// liveness constraints depends on the variance of types with respect to each contained region.
78+
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
79+
80+
/// The regions that outlive free regions are used to distinguish relevant live locals from
81+
/// boring locals. A boring local is one whose type contains only such regions. Polonius
82+
/// currently has more boring locals than NLLs so we record the latter to use in errors and
83+
/// diagnostics, to focus on the locals we consider relevant and match NLL diagnostics.
84+
pub(crate) boring_nll_locals: FxHashSet<Local>,
85+
}
86+
87+
/// This struct holds the data needed to create the Polonius localized constraints. Its data is
88+
/// transferred and converted from the [PoloniusLivenessContext] at the end of MIR typeck.
6189
pub(crate) struct PoloniusContext {
90+
/// The liveness data we recorded during MIR typeck.
91+
liveness_context: PoloniusLivenessContext,
92+
6293
/// The set of regions that are live at a given point in the CFG, used to create localized
6394
/// outlives constraints between regions that are live at connected points in the CFG.
64-
live_regions: Option<SparseBitMatrix<PointIndex, RegionVid>>,
95+
live_regions: SparseBitMatrix<PointIndex, RegionVid>,
96+
}
6597

66-
/// The expected edge direction per live region: the kind of directed edge we'll create as
67-
/// liveness constraints depends on the variance of types with respect to each contained region.
68-
live_region_variances: BTreeMap<RegionVid, ConstraintDirection>,
98+
/// This struct holds the data needed by the borrowck error computation and diagnostics. Its data is
99+
/// computed from the [PoloniusContext] when computing NLL regions.
100+
pub(crate) struct PoloniusDiagnosticsContext {
101+
/// The localized outlives constraints that were computed in the main analysis.
102+
localized_outlives_constraints: LocalizedOutlivesConstraintSet,
103+
104+
/// The liveness data computed during MIR typeck: [PoloniusLivenessContext::boring_nll_locals].
105+
pub(crate) boring_nll_locals: FxHashSet<Local>,
69106
}
70107

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

85122
impl PoloniusContext {
86-
pub(crate) fn new() -> PoloniusContext {
87-
Self { live_region_variances: BTreeMap::new(), live_regions: None }
123+
/// Unlike NLLs, in polonius we traverse the cfg to look for regions live across an edge, so we
124+
/// need to transpose the "points where each region is live" matrix to a "live regions per point"
125+
/// matrix.
126+
// FIXME: avoid this conversion by always storing liveness data in this shape in the rest of
127+
// borrowck.
128+
pub(crate) fn create_from_liveness(
129+
liveness_context: PoloniusLivenessContext,
130+
num_regions: usize,
131+
points_per_live_region: &SparseIntervalMatrix<RegionVid, PointIndex>,
132+
) -> PoloniusContext {
133+
let mut live_regions_per_point = SparseBitMatrix::new(num_regions);
134+
for region in points_per_live_region.rows() {
135+
for point in points_per_live_region.row(region).unwrap().iter() {
136+
live_regions_per_point.insert(point, region);
137+
}
138+
}
139+
140+
PoloniusContext { live_regions: live_regions_per_point, liveness_context }
88141
}
89142

90143
/// Computes live loans using the set of loans model for `-Zpolonius=next`.
@@ -95,13 +148,18 @@ impl PoloniusContext {
95148
///
96149
/// Then, this graph is traversed, and combined with kills, reachability is recorded as loan
97150
/// liveness, to be used by the loan scope and active loans computations.
151+
///
152+
/// The constraint data will be used to compute errors and diagnostics.
98153
pub(crate) fn compute_loan_liveness<'tcx>(
99-
&self,
154+
self,
100155
tcx: TyCtxt<'tcx>,
101156
regioncx: &mut RegionInferenceContext<'tcx>,
102157
body: &Body<'tcx>,
103158
borrow_set: &BorrowSet<'tcx>,
104-
) -> LocalizedOutlivesConstraintSet {
159+
) -> PoloniusDiagnosticsContext {
160+
let PoloniusLivenessContext { live_region_variances, boring_nll_locals } =
161+
self.liveness_context;
162+
105163
let mut localized_outlives_constraints = LocalizedOutlivesConstraintSet::default();
106164
convert_typeck_constraints(
107165
tcx,
@@ -112,14 +170,11 @@ impl PoloniusContext {
112170
&mut localized_outlives_constraints,
113171
);
114172

115-
let live_regions = self.live_regions.as_ref().expect(
116-
"live regions per-point data should have been created at the end of MIR typeck",
117-
);
118173
create_liveness_constraints(
119174
body,
120175
regioncx.liveness_constraints(),
121-
live_regions,
122-
&self.live_region_variances,
176+
&self.live_regions,
177+
&live_region_variances,
123178
regioncx.universal_regions(),
124179
&mut localized_outlives_constraints,
125180
);
@@ -136,6 +191,6 @@ impl PoloniusContext {
136191
);
137192
regioncx.record_live_loans(live_loans);
138193

139-
localized_outlives_constraints
194+
PoloniusDiagnosticsContext { localized_outlives_constraints, boring_nll_locals }
140195
}
141196
}

0 commit comments

Comments
 (0)