diff --git a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs index 841cb782bc3bd..3e474225afdfb 100644 --- a/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs +++ b/compiler/rustc_borrowck/src/diagnostics/explain_borrow.rs @@ -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) @@ -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); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 077d8f49df88c..8ddc8add67589 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -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; @@ -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, @@ -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>, @@ -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. @@ -329,7 +332,7 @@ fn do_mir_borrowck<'tcx>( body, ®ioncx, &borrow_set, - localized_outlives_constraints, + polonius_diagnostics.as_ref(), &opt_closure_req, ); @@ -579,6 +582,9 @@ struct MirBorrowckCtxt<'a, 'infcx, 'tcx> { diags_buffer: &'a mut BorrowckDiagnosticsBuffer<'infcx, 'tcx>, move_errors: Vec>, + + /// When using `-Zpolonius=next`: the data used to compute errors and diagnostics. + polonius_diagnostics: Option<&'a PoloniusDiagnosticsContext>, } // Check that: diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 35264bd1a7075..2031579dfd50a 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -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, }; @@ -46,8 +46,9 @@ pub(crate) struct NllOutput<'tcx> { pub opt_closure_req: Option>, pub nll_errors: RegionErrors<'tcx>, - /// When using `-Zpolonius=next`: the localized typeck and liveness constraints. - pub localized_outlives_constraints: Option, + /// When using `-Zpolonius=next`: the data used to compute errors and diagnostics, e.g. + /// localized typeck and liveness constraints. + pub polonius_diagnostics: Option, } /// 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>( // 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) }); @@ -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, } } diff --git a/compiler/rustc_borrowck/src/polonius/dump.rs b/compiler/rustc_borrowck/src/polonius/dump.rs index 6d32ee17f4c2a..5f9fa3612b8d1 100644 --- a/compiler/rustc_borrowck/src/polonius/dump.rs +++ b/compiler/rustc_borrowck/src/polonius/dump.rs @@ -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}; @@ -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, + polonius_diagnostics: Option<&PoloniusDiagnosticsContext>, closure_region_requirements: &Option>, ) { let tcx = infcx.tcx; @@ -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)?; @@ -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, )?; @@ -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>, out: &mut dyn io::Write, ) -> io::Result<()> { diff --git a/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs b/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs index 75ee29c9d0d50..6ab09f731c078 100644 --- a/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs +++ b/compiler/rustc_borrowck/src/polonius/liveness_constraints.rs @@ -1,7 +1,6 @@ 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}; @@ -9,12 +8,12 @@ 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, @@ -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, - ) { - 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 diff --git a/compiler/rustc_borrowck/src/polonius/mod.rs b/compiler/rustc_borrowck/src/polonius/mod.rs index 502c868194af2..142ef8ba28eff 100644 --- a/compiler/rustc_borrowck/src/polonius/mod.rs +++ b/compiler/rustc_borrowck/src/polonius/mod.rs @@ -32,6 +32,16 @@ //! - //! - //! +//! +//! 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; @@ -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; @@ -57,15 +69,40 @@ use crate::{BorrowSet, RegionInferenceContext}; pub(crate) type LiveLoans = SparseBitMatrix; -/// 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, + + /// 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, +} + +/// 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>, + live_regions: SparseBitMatrix, +} - /// 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, +/// 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, } /// The direction a constraint can flow into. Used to create liveness constraints according to @@ -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, + ) -> 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`. @@ -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, @@ -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, ); @@ -136,6 +191,6 @@ impl PoloniusContext { ); regioncx.record_live_loans(live_loans); - localized_outlives_constraints + PoloniusDiagnosticsContext { localized_outlives_constraints, boring_nll_locals } } } diff --git a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs index 4e0b2a4e29681..dcc179030020d 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/mod.rs @@ -14,7 +14,7 @@ use tracing::debug; use super::TypeChecker; use crate::constraints::OutlivesConstraintSet; -use crate::polonius::PoloniusContext; +use crate::polonius::PoloniusLivenessContext; use crate::region_infer::values::LivenessValues; use crate::universal_regions::UniversalRegions; @@ -38,19 +38,24 @@ pub(super) fn generate<'a, 'tcx>( ) { debug!("liveness::generate"); + let mut free_regions = regions_that_outlive_free_regions( + typeck.infcx.num_region_vars(), + &typeck.universal_regions, + &typeck.constraints.outlives_constraints, + ); + // NLLs can avoid computing some liveness data here because its constraints are // location-insensitive, but that doesn't work in polonius: locals whose type contains a region // that outlives a free region are not necessarily live everywhere in a flow-sensitive setting, // unlike NLLs. - let free_regions = if !typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() { - regions_that_outlive_free_regions( - typeck.infcx.num_region_vars(), - &typeck.universal_regions, - &typeck.constraints.outlives_constraints, - ) - } else { - typeck.universal_regions.universal_regions_iter().collect() - }; + // We do record these regions in the polonius context, since they're used to differentiate + // relevant and boring locals, which is a key distinction used later in diagnostics. + if typeck.tcx().sess.opts.unstable_opts.polonius.is_next_enabled() { + let (_, boring_locals) = compute_relevant_live_locals(typeck.tcx(), &free_regions, body); + typeck.polonius_liveness.as_mut().unwrap().boring_nll_locals = + boring_locals.into_iter().collect(); + free_regions = typeck.universal_regions.universal_regions_iter().collect(); + } let (relevant_live_locals, boring_locals) = compute_relevant_live_locals(typeck.tcx(), &free_regions, body); @@ -70,7 +75,7 @@ pub(super) fn generate<'a, 'tcx>( typeck.tcx(), &mut typeck.constraints.liveness_constraints, &typeck.universal_regions, - &mut typeck.polonius_context, + &mut typeck.polonius_liveness, body, ); } @@ -147,11 +152,11 @@ fn record_regular_live_regions<'tcx>( tcx: TyCtxt<'tcx>, liveness_constraints: &mut LivenessValues, universal_regions: &UniversalRegions<'tcx>, - polonius_context: &mut Option, + polonius_liveness: &mut Option, body: &Body<'tcx>, ) { let mut visitor = - LiveVariablesVisitor { tcx, liveness_constraints, universal_regions, polonius_context }; + LiveVariablesVisitor { tcx, liveness_constraints, universal_regions, polonius_liveness }; for (bb, data) in body.basic_blocks.iter_enumerated() { visitor.visit_basic_block_data(bb, data); } @@ -162,7 +167,7 @@ struct LiveVariablesVisitor<'a, 'tcx> { tcx: TyCtxt<'tcx>, liveness_constraints: &'a mut LivenessValues, universal_regions: &'a UniversalRegions<'tcx>, - polonius_context: &'a mut Option, + polonius_liveness: &'a mut Option, } impl<'a, 'tcx> Visitor<'tcx> for LiveVariablesVisitor<'a, 'tcx> { @@ -214,8 +219,8 @@ impl<'a, 'tcx> LiveVariablesVisitor<'a, 'tcx> { }); // When using `-Zpolonius=next`, we record the variance of each live region. - if let Some(polonius_context) = self.polonius_context { - polonius_context.record_live_region_variance(self.tcx, self.universal_regions, value); + if let Some(polonius_liveness) = self.polonius_liveness { + polonius_liveness.record_live_region_variance(self.tcx, self.universal_regions, value); } } } diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index c564d85616e25..62d49a62744e7 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -580,8 +580,8 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { }); // When using `-Zpolonius=next`, we record the variance of each live region. - if let Some(polonius_context) = typeck.polonius_context { - polonius_context.record_live_region_variance( + if let Some(polonius_liveness) = typeck.polonius_liveness.as_mut() { + polonius_liveness.record_live_region_variance( typeck.infcx.tcx, typeck.universal_regions, value, diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 92492bfdb8d31..78aa38e9e48f4 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -48,8 +48,8 @@ use crate::borrow_set::BorrowSet; use crate::constraints::{OutlivesConstraint, OutlivesConstraintSet}; use crate::diagnostics::UniverseInfo; use crate::member_constraints::MemberConstraintSet; -use crate::polonius::PoloniusContext; use crate::polonius::legacy::{PoloniusFacts, PoloniusLocationTable}; +use crate::polonius::{PoloniusContext, PoloniusLivenessContext}; use crate::region_infer::TypeTest; use crate::region_infer::values::{LivenessValues, PlaceholderIndex, PlaceholderIndices}; use crate::renumber::RegionCtxt; @@ -148,8 +148,8 @@ pub(crate) fn type_check<'a, 'tcx>( debug!(?normalized_inputs_and_output); - let mut polonius_context = if infcx.tcx.sess.opts.unstable_opts.polonius.is_next_enabled() { - Some(PoloniusContext::new()) + let polonius_liveness = if infcx.tcx.sess.opts.unstable_opts.polonius.is_next_enabled() { + Some(PoloniusLivenessContext::default()) } else { None }; @@ -168,7 +168,7 @@ pub(crate) fn type_check<'a, 'tcx>( polonius_facts, borrow_set, constraints: &mut constraints, - polonius_context: &mut polonius_context, + polonius_liveness, }; typeck.check_user_type_annotations(); @@ -185,11 +185,14 @@ pub(crate) fn type_check<'a, 'tcx>( let opaque_type_values = opaque_types::take_opaques_and_register_member_constraints(&mut typeck); - if let Some(polonius_context) = typeck.polonius_context.as_mut() { - let num_regions = infcx.num_region_vars(); - let points_per_live_region = typeck.constraints.liveness_constraints.points(); - polonius_context.record_live_regions_per_point(num_regions, points_per_live_region); - } + // We're done with typeck, we can finalize the polonius liveness context for region inference. + let polonius_context = typeck.polonius_liveness.take().map(|liveness_context| { + PoloniusContext::create_from_liveness( + liveness_context, + infcx.num_region_vars(), + typeck.constraints.liveness_constraints.points(), + ) + }); MirTypeckResults { constraints, @@ -583,8 +586,8 @@ struct TypeChecker<'a, 'tcx> { polonius_facts: &'a mut Option, borrow_set: &'a BorrowSet<'tcx>, constraints: &'a mut MirTypeckRegionConstraints<'tcx>, - /// When using `-Zpolonius=next`, the helper data used to create polonius constraints. - polonius_context: &'a mut Option, + /// When using `-Zpolonius=next`, the liveness helper data used to create polonius constraints. + polonius_liveness: Option, } /// Holder struct for passing results from MIR typeck to the rest of the non-lexical regions diff --git a/compiler/rustc_const_eval/src/const_eval/valtrees.rs b/compiler/rustc_const_eval/src/const_eval/valtrees.rs index 4d625f76aba2a..c35910a706b21 100644 --- a/compiler/rustc_const_eval/src/const_eval/valtrees.rs +++ b/compiler/rustc_const_eval/src/const_eval/valtrees.rs @@ -273,59 +273,63 @@ pub(crate) fn eval_to_valtree<'tcx>( /// Converts a `ValTree` to a `ConstValue`, which is needed after mir /// construction has finished. // FIXME(valtrees): Merge `valtree_to_const_value` and `valtree_into_mplace` into one function -// FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately. #[instrument(skip(tcx), level = "debug", ret)] pub fn valtree_to_const_value<'tcx>( tcx: TyCtxt<'tcx>, typing_env: ty::TypingEnv<'tcx>, - ty: Ty<'tcx>, - valtree: ty::ValTree<'tcx>, + cv: ty::Value<'tcx>, ) -> mir::ConstValue<'tcx> { // Basic idea: We directly construct `Scalar` values from trivial `ValTree`s // (those for constants with type bool, int, uint, float or char). // For all other types we create an `MPlace` and fill that by walking // the `ValTree` and using `place_projection` and `place_field` to // create inner `MPlace`s which are filled recursively. - // FIXME Does this need an example? - match *ty.kind() { + // FIXME: Does this need an example? + match *cv.ty.kind() { ty::FnDef(..) => { - assert!(valtree.unwrap_branch().is_empty()); + assert!(cv.valtree.unwrap_branch().is_empty()); mir::ConstValue::ZeroSized } ty::Bool | ty::Int(_) | ty::Uint(_) | ty::Float(_) | ty::Char | ty::RawPtr(_, _) => { - match valtree { + match cv.valtree { ty::ValTree::Leaf(scalar_int) => mir::ConstValue::Scalar(Scalar::Int(scalar_int)), ty::ValTree::Branch(_) => bug!( "ValTrees for Bool, Int, Uint, Float, Char or RawPtr should have the form ValTree::Leaf" ), } } - ty::Pat(ty, _) => valtree_to_const_value(tcx, typing_env, ty, valtree), + ty::Pat(ty, _) => { + let cv = ty::Value { valtree: cv.valtree, ty }; + valtree_to_const_value(tcx, typing_env, cv) + } ty::Ref(_, inner_ty, _) => { let mut ecx = mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No); - let imm = valtree_to_ref(&mut ecx, valtree, inner_ty); - let imm = - ImmTy::from_immediate(imm, tcx.layout_of(typing_env.as_query_input(ty)).unwrap()); + let imm = valtree_to_ref(&mut ecx, cv.valtree, inner_ty); + let imm = ImmTy::from_immediate( + imm, + tcx.layout_of(typing_env.as_query_input(cv.ty)).unwrap(), + ); op_to_const(&ecx, &imm.into(), /* for diagnostics */ false) } ty::Tuple(_) | ty::Array(_, _) | ty::Adt(..) => { - let layout = tcx.layout_of(typing_env.as_query_input(ty)).unwrap(); + let layout = tcx.layout_of(typing_env.as_query_input(cv.ty)).unwrap(); if layout.is_zst() { // Fast path to avoid some allocations. return mir::ConstValue::ZeroSized; } if layout.backend_repr.is_scalar() - && (matches!(ty.kind(), ty::Tuple(_)) - || matches!(ty.kind(), ty::Adt(def, _) if def.is_struct())) + && (matches!(cv.ty.kind(), ty::Tuple(_)) + || matches!(cv.ty.kind(), ty::Adt(def, _) if def.is_struct())) { // A Scalar tuple/struct; we can avoid creating an allocation. - let branches = valtree.unwrap_branch(); + let branches = cv.valtree.unwrap_branch(); // Find the non-ZST field. (There can be aligned ZST!) for (i, &inner_valtree) in branches.iter().enumerate() { let field = layout.field(&LayoutCx::new(tcx, typing_env), i); if !field.is_zst() { - return valtree_to_const_value(tcx, typing_env, field.ty, inner_valtree); + let cv = ty::Value { valtree: inner_valtree, ty: field.ty }; + return valtree_to_const_value(tcx, typing_env, cv); } } bug!("could not find non-ZST field during in {layout:#?}"); @@ -335,9 +339,9 @@ pub fn valtree_to_const_value<'tcx>( mk_eval_cx_to_read_const_val(tcx, DUMMY_SP, typing_env, CanAccessMutGlobal::No); // Need to create a place for this valtree. - let place = create_valtree_place(&mut ecx, layout, valtree); + let place = create_valtree_place(&mut ecx, layout, cv.valtree); - valtree_into_mplace(&mut ecx, &place, valtree); + valtree_into_mplace(&mut ecx, &place, cv.valtree); dump_place(&ecx, &place); intern_const_alloc_recursive(&mut ecx, InternKind::Constant, &place).unwrap(); @@ -362,7 +366,7 @@ pub fn valtree_to_const_value<'tcx>( | ty::Slice(_) | ty::Dynamic(..) | ty::UnsafeBinder(_) => { - bug!("no ValTree should have been created for type {:?}", ty.kind()) + bug!("no ValTree should have been created for type {:?}", cv.ty.kind()) } } } diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index ecf9745b77945..b44d2a01d57c0 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -46,14 +46,8 @@ pub fn provide(providers: &mut Providers) { }; providers.hooks.try_destructure_mir_constant_for_user_output = const_eval::try_destructure_mir_constant_for_user_output; - providers.valtree_to_const_val = |tcx, cv| { - const_eval::valtree_to_const_value( - tcx, - ty::TypingEnv::fully_monomorphized(), - cv.ty, - cv.valtree, - ) - }; + providers.valtree_to_const_val = + |tcx, cv| const_eval::valtree_to_const_value(tcx, ty::TypingEnv::fully_monomorphized(), cv); providers.check_validity_requirement = |tcx, (init_kind, param_env_and_ty)| { util::check_validity_requirement(tcx, init_kind, param_env_and_ty) }; diff --git a/compiler/rustc_data_structures/src/vec_cache.rs b/compiler/rustc_data_structures/src/vec_cache.rs index eb251b587c804..2ff60ab7f36f9 100644 --- a/compiler/rustc_data_structures/src/vec_cache.rs +++ b/compiler/rustc_data_structures/src/vec_cache.rs @@ -206,6 +206,19 @@ impl SlotIndex { } } +/// In-memory cache for queries whose keys are densely-numbered IDs +/// (e.g `CrateNum`, `LocalDefId`), and can therefore be used as indices +/// into a dense vector of cached values. +/// +/// (As of [#124780] the underlying storage is not an actual `Vec`, but rather +/// a series of increasingly-large buckets, for improved performance when the +/// parallel frontend is using multiple threads.) +/// +/// Each entry in the cache stores the query's return value (`V`), and also +/// an associated index (`I`), which in practice is a `DepNodeIndex` used for +/// query dependency tracking. +/// +/// [#124780]: https://github.com/rust-lang/rust/pull/124780 pub struct VecCache { // Entries per bucket: // Bucket 0: 4096 2^12 diff --git a/compiler/rustc_middle/src/mir/pretty.rs b/compiler/rustc_middle/src/mir/pretty.rs index 09d7e60e19941..aa8ec3aff040a 100644 --- a/compiler/rustc_middle/src/mir/pretty.rs +++ b/compiler/rustc_middle/src/mir/pretty.rs @@ -12,6 +12,7 @@ use rustc_middle::mir::interpret::{ use rustc_middle::mir::visit::Visitor; use rustc_middle::mir::*; use tracing::trace; +use ty::print::PrettyPrinter; use super::graphviz::write_mir_fn_graphviz; use crate::mir::interpret::ConstAllocation; @@ -1439,10 +1440,10 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { }) }; - // FIXME: call pretty_print_const_valtree? - let fmt_valtree = |valtree: &ty::ValTree<'tcx>| match valtree { - ty::ValTree::Leaf(leaf) => format!("Leaf({leaf:?})"), - ty::ValTree::Branch(_) => "Branch(..)".to_string(), + let fmt_valtree = |cv: &ty::Value<'tcx>| { + let mut cx = FmtPrinter::new(self.tcx, Namespace::ValueNS); + cx.pretty_print_const_valtree(*cv, /*print_ty*/ true).unwrap(); + cx.into_buffer() }; let val = match const_ { @@ -1452,7 +1453,7 @@ impl<'tcx> Visitor<'tcx> for ExtraComments<'tcx> { format!("ty::Unevaluated({}, {:?})", self.tcx.def_path_str(uv.def), uv.args,) } ty::ConstKind::Value(cv) => { - format!("ty::Valtree({})", fmt_valtree(&cv.valtree)) + format!("ty::Valtree({})", fmt_valtree(&cv)) } // No `ty::` prefix since we also use this to represent errors from `mir::Unevaluated`. ty::ConstKind::Error(_) => "Error".to_string(), diff --git a/compiler/rustc_middle/src/query/keys.rs b/compiler/rustc_middle/src/query/keys.rs index 949d8303385cb..1489d57aba645 100644 --- a/compiler/rustc_middle/src/query/keys.rs +++ b/compiler/rustc_middle/src/query/keys.rs @@ -20,6 +20,12 @@ pub struct LocalCrate; /// The `Key` trait controls what types can legally be used as the key /// for a query. pub trait Key: Sized { + /// The type of in-memory cache to use for queries with this key type. + /// + /// In practice the cache type must implement [`QueryCache`], though that + /// constraint is not enforced here. + /// + /// [`QueryCache`]: rustc_query_system::query::QueryCache // N.B. Most of the keys down below have `type Cache = DefaultCache;`, // it would be reasonable to use associated type defaults, to remove the duplication... // diff --git a/compiler/rustc_middle/src/ty/consts/valtree.rs b/compiler/rustc_middle/src/ty/consts/valtree.rs index d914b7576dc49..5905076c4d08c 100644 --- a/compiler/rustc_middle/src/ty/consts/valtree.rs +++ b/compiler/rustc_middle/src/ty/consts/valtree.rs @@ -78,30 +78,6 @@ impl<'tcx> ValTree<'tcx> { Self::Branch(_) => None, } } - - /// Get the values inside the ValTree as a slice of bytes. This only works for - /// constants with types &str, &[u8], or [u8; _]. - pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Option<&'tcx [u8]> { - match ty.kind() { - ty::Ref(_, inner_ty, _) => match inner_ty.kind() { - // `&str` can be interpreted as raw bytes - ty::Str => {} - // `&[u8]` can be interpreted as raw bytes - ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {} - // other `&_` can't be interpreted as raw bytes - _ => return None, - }, - // `[u8; N]` can be interpreted as raw bytes - ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {} - // Otherwise, type cannot be interpreted as raw bytes - _ => return None, - } - - Some( - tcx.arena - .alloc_from_iter(self.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().to_u8())), - ) - } } /// A type-level constant value. @@ -143,6 +119,29 @@ impl<'tcx> Value<'tcx> { } self.valtree.try_to_scalar_int().map(|s| s.to_target_usize(tcx)) } + + /// Get the values inside the ValTree as a slice of bytes. This only works for + /// constants with types &str, &[u8], or [u8; _]. + pub fn try_to_raw_bytes(self, tcx: TyCtxt<'tcx>) -> Option<&'tcx [u8]> { + match self.ty.kind() { + ty::Ref(_, inner_ty, _) => match inner_ty.kind() { + // `&str` can be interpreted as raw bytes + ty::Str => {} + // `&[u8]` can be interpreted as raw bytes + ty::Slice(slice_ty) if *slice_ty == tcx.types.u8 => {} + // other `&_` can't be interpreted as raw bytes + _ => return None, + }, + // `[u8; N]` can be interpreted as raw bytes + ty::Array(array_ty, _) if *array_ty == tcx.types.u8 => {} + // Otherwise, type cannot be interpreted as raw bytes + _ => return None, + } + + Some(tcx.arena.alloc_from_iter( + self.valtree.unwrap_branch().into_iter().map(|v| v.unwrap_leaf().to_u8()), + )) + } } impl<'tcx> rustc_type_ir::inherent::ValueConst> for Value<'tcx> { diff --git a/compiler/rustc_middle/src/ty/print/pretty.rs b/compiler/rustc_middle/src/ty/print/pretty.rs index 6c8591dae895b..3431081b189e4 100644 --- a/compiler/rustc_middle/src/ty/print/pretty.rs +++ b/compiler/rustc_middle/src/ty/print/pretty.rs @@ -1487,7 +1487,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { }, ty::ConstKind::Param(ParamConst { name, .. }) => p!(write("{}", name)), ty::ConstKind::Value(cv) => { - return self.pretty_print_const_valtree(cv.valtree, cv.ty, print_ty); + return self.pretty_print_const_valtree(cv, print_ty); } ty::ConstKind::Bound(debruijn, bound_var) => { @@ -1787,48 +1787,47 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { Ok(()) } - // FIXME(valtrees): Accept `ty::Value` instead of `Ty` and `ty::ValTree` separately. fn pretty_print_const_valtree( &mut self, - valtree: ty::ValTree<'tcx>, - ty: Ty<'tcx>, + cv: ty::Value<'tcx>, print_ty: bool, ) -> Result<(), PrintError> { define_scoped_cx!(self); if self.should_print_verbose() { - p!(write("ValTree({:?}: ", valtree), print(ty), ")"); + p!(write("ValTree({:?}: ", cv.valtree), print(cv.ty), ")"); return Ok(()); } let u8_type = self.tcx().types.u8; - match (valtree, ty.kind()) { + match (cv.valtree, cv.ty.kind()) { (ty::ValTree::Branch(_), ty::Ref(_, inner_ty, _)) => match inner_ty.kind() { ty::Slice(t) if *t == u8_type => { - let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| { + let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| { bug!( "expected to convert valtree {:?} to raw bytes for type {:?}", - valtree, + cv.valtree, t ) }); return self.pretty_print_byte_str(bytes); } ty::Str => { - let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| { - bug!("expected to convert valtree to raw bytes for type {:?}", ty) + let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| { + bug!("expected to convert valtree to raw bytes for type {:?}", cv.ty) }); p!(write("{:?}", String::from_utf8_lossy(bytes))); return Ok(()); } _ => { + let cv = ty::Value { valtree: cv.valtree, ty: *inner_ty }; p!("&"); - p!(pretty_print_const_valtree(valtree, *inner_ty, print_ty)); + p!(pretty_print_const_valtree(cv, print_ty)); return Ok(()); } }, (ty::ValTree::Branch(_), ty::Array(t, _)) if *t == u8_type => { - let bytes = valtree.try_to_raw_bytes(self.tcx(), ty).unwrap_or_else(|| { + let bytes = cv.try_to_raw_bytes(self.tcx()).unwrap_or_else(|| { bug!("expected to convert valtree to raw bytes for type {:?}", t) }); p!("*"); @@ -1837,10 +1836,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // Aggregates, printed as array/tuple/struct/variant construction syntax. (ty::ValTree::Branch(_), ty::Array(..) | ty::Tuple(..) | ty::Adt(..)) => { - let contents = - self.tcx().destructure_const(ty::Const::new_value(self.tcx(), valtree, ty)); + let contents = self.tcx().destructure_const(ty::Const::new_value( + self.tcx(), + cv.valtree, + cv.ty, + )); let fields = contents.fields.iter().copied(); - match *ty.kind() { + match *cv.ty.kind() { ty::Array(..) => { p!("[", comma_sep(fields), "]"); } @@ -1857,7 +1859,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { write!(this, "unreachable()")?; Ok(()) }, - |this| this.print_type(ty), + |this| this.print_type(cv.ty), ": ", )?; } @@ -1894,7 +1896,7 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { return self.pretty_print_const_scalar_int(leaf, *inner_ty, print_ty); } (ty::ValTree::Leaf(leaf), _) => { - return self.pretty_print_const_scalar_int(leaf, ty, print_ty); + return self.pretty_print_const_scalar_int(leaf, cv.ty, print_ty); } // FIXME(oli-obk): also pretty print arrays and other aggregate constants by reading // their fields instead of just dumping the memory. @@ -1902,13 +1904,13 @@ pub trait PrettyPrinter<'tcx>: Printer<'tcx> + fmt::Write { } // fallback - if valtree == ty::ValTree::zst() { + if cv.valtree == ty::ValTree::zst() { p!(write("")); } else { - p!(write("{:?}", valtree)); + p!(write("{:?}", cv.valtree)); } if print_ty { - p!(": ", print(ty)); + p!(": ", print(cv.ty)); } Ok(()) } diff --git a/compiler/rustc_middle/src/ty/structural_impls.rs b/compiler/rustc_middle/src/ty/structural_impls.rs index 9e9de4fb06443..03b26b4453800 100644 --- a/compiler/rustc_middle/src/ty/structural_impls.rs +++ b/compiler/rustc_middle/src/ty/structural_impls.rs @@ -170,7 +170,7 @@ impl<'tcx> fmt::Debug for ty::Const<'tcx> { bug!("we checked that this is a valtree") }; let mut cx = FmtPrinter::new(tcx, Namespace::ValueNS); - cx.pretty_print_const_valtree(cv.valtree, cv.ty, /*print_ty*/ true)?; + cx.pretty_print_const_valtree(cv, /*print_ty*/ true)?; f.write_str(&cx.into_buffer()) }); } diff --git a/compiler/rustc_query_system/src/query/caches.rs b/compiler/rustc_query_system/src/query/caches.rs index e6f3d97742d31..e11123dff26a7 100644 --- a/compiler/rustc_query_system/src/query/caches.rs +++ b/compiler/rustc_query_system/src/query/caches.rs @@ -11,18 +11,30 @@ use rustc_span::def_id::{DefId, DefIndex}; use crate::dep_graph::DepNodeIndex; +/// Trait for types that serve as an in-memory cache for query results, +/// for a given key (argument) type and value (return) type. +/// +/// Types implementing this trait are associated with actual key/value types +/// by the `Cache` associated type of the `rustc_middle::query::Key` trait. pub trait QueryCache: Sized { type Key: Hash + Eq + Copy + Debug; type Value: Copy; - /// Checks if the query is already computed and in the cache. + /// Returns the cached value (and other information) associated with the + /// given key, if it is present in the cache. fn lookup(&self, key: &Self::Key) -> Option<(Self::Value, DepNodeIndex)>; + /// Adds a key/value entry to this cache. + /// + /// Called by some part of the query system, after having obtained the + /// value by executing the query or loading a cached value from disk. fn complete(&self, key: Self::Key, value: Self::Value, index: DepNodeIndex); fn iter(&self, f: &mut dyn FnMut(&Self::Key, &Self::Value, DepNodeIndex)); } +/// In-memory cache for queries whose keys aren't suitable for any of the +/// more specialized kinds of cache. Backed by a sharded hashmap. pub struct DefaultCache { cache: Sharded>, } @@ -67,6 +79,8 @@ where } } +/// In-memory cache for queries whose key type only has one value (e.g. `()`). +/// The cache therefore only needs to store one query return value. pub struct SingleCache { cache: OnceLock<(V, DepNodeIndex)>, } @@ -101,6 +115,10 @@ where } } +/// In-memory cache for queries whose key is a [`DefId`]. +/// +/// Selects between one of two internal caches, depending on whether the key +/// is a local ID or foreign-crate ID. pub struct DefIdCache { /// Stores the local DefIds in a dense map. Local queries are much more often dense, so this is /// a win over hashing query keys at marginal memory cost (~5% at most) compared to FxHashMap. diff --git a/compiler/rustc_query_system/src/query/plumbing.rs b/compiler/rustc_query_system/src/query/plumbing.rs index 6fb5e37d2d066..18aae8c00b247 100644 --- a/compiler/rustc_query_system/src/query/plumbing.rs +++ b/compiler/rustc_query_system/src/query/plumbing.rs @@ -222,10 +222,10 @@ pub struct CycleError { pub cycle: Vec, } -/// Checks if the query is already computed and in the cache. -/// It returns the shard index and a lock guard to the shard, -/// which will be used if the query is not in the cache and we need -/// to compute it. +/// Checks whether there is already a value for this key in the in-memory +/// query cache, returning that value if present. +/// +/// (Also performs some associated bookkeeping, if a value was found.) #[inline(always)] pub fn try_get_cached(tcx: Tcx, cache: &C, key: &C::Key) -> Option where diff --git a/compiler/rustc_symbol_mangling/src/v0.rs b/compiler/rustc_symbol_mangling/src/v0.rs index 7b040a8b2c411..0ac6f17b97bd0 100644 --- a/compiler/rustc_symbol_mangling/src/v0.rs +++ b/compiler/rustc_symbol_mangling/src/v0.rs @@ -649,7 +649,8 @@ impl<'tcx> Printer<'tcx> for SymbolMangler<'tcx> { // HACK(jaic1): hide the `str` type behind a reference // for the following transformation from valtree to raw bytes let ref_ty = Ty::new_imm_ref(tcx, tcx.lifetimes.re_static, ct_ty); - let slice = valtree.try_to_raw_bytes(tcx, ref_ty).unwrap_or_else(|| { + let cv = ty::Value { ty: ref_ty, valtree }; + let slice = cv.try_to_raw_bytes(tcx).unwrap_or_else(|| { bug!("expected to get raw bytes from valtree {:?} for type {:}", valtree, ct_ty) }); let s = std::str::from_utf8(slice).expect("non utf8 str from MIR interpreter"); diff --git a/library/core/src/cell/once.rs b/library/core/src/cell/once.rs index 6a85791916a61..c6c96571d33c9 100644 --- a/library/core/src/cell/once.rs +++ b/library/core/src/cell/once.rs @@ -8,6 +8,9 @@ use crate::{fmt, mem}; /// only immutable references can be obtained unless one has a mutable reference to the cell /// itself. In the same vein, the cell can only be re-initialized with such a mutable reference. /// +/// A `OnceCell` can be thought of as a safe abstraction over uninitialized data that becomes +/// initialized once written. +/// /// For a thread-safe version of this struct, see [`std::sync::OnceLock`]. /// /// [`RefCell`]: crate::cell::RefCell @@ -35,7 +38,7 @@ pub struct OnceCell { } impl OnceCell { - /// Creates a new empty cell. + /// Creates a new uninitialized cell. #[inline] #[must_use] #[stable(feature = "once_cell", since = "1.70.0")] @@ -46,7 +49,7 @@ impl OnceCell { /// Gets the reference to the underlying value. /// - /// Returns `None` if the cell is empty. + /// Returns `None` if the cell is uninitialized. #[inline] #[stable(feature = "once_cell", since = "1.70.0")] pub fn get(&self) -> Option<&T> { @@ -56,19 +59,19 @@ impl OnceCell { /// Gets the mutable reference to the underlying value. /// - /// Returns `None` if the cell is empty. + /// Returns `None` if the cell is uninitialized. #[inline] #[stable(feature = "once_cell", since = "1.70.0")] pub fn get_mut(&mut self) -> Option<&mut T> { self.inner.get_mut().as_mut() } - /// Sets the contents of the cell to `value`. + /// Initializes the contents of the cell to `value`. /// /// # Errors /// - /// This method returns `Ok(())` if the cell was empty and `Err(value)` if - /// it was full. + /// This method returns `Ok(())` if the cell was uninitialized + /// and `Err(value)` if it was already initialized. /// /// # Examples /// @@ -92,13 +95,13 @@ impl OnceCell { } } - /// Sets the contents of the cell to `value` if the cell was empty, then - /// returns a reference to it. + /// Initializes the contents of the cell to `value` if the cell was + /// uninitialized, then returns a reference to it. /// /// # Errors /// - /// This method returns `Ok(&value)` if the cell was empty and - /// `Err(¤t_value, value)` if it was full. + /// This method returns `Ok(&value)` if the cell was uninitialized + /// and `Err((¤t_value, value))` if it was already initialized. /// /// # Examples /// @@ -130,12 +133,12 @@ impl OnceCell { Ok(slot.insert(value)) } - /// Gets the contents of the cell, initializing it with `f` - /// if the cell was empty. + /// Gets the contents of the cell, initializing it to `f()` + /// if the cell was uninitialized. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. Doing @@ -164,11 +167,11 @@ impl OnceCell { } /// Gets the mutable reference of the contents of the cell, - /// initializing it with `f` if the cell was empty. + /// initializing it to `f()` if the cell was uninitialized. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// # Examples @@ -199,13 +202,13 @@ impl OnceCell { } } - /// Gets the contents of the cell, initializing it with `f` if - /// the cell was empty. If the cell was empty and `f` failed, an - /// error is returned. + /// Gets the contents of the cell, initializing it to `f()` if + /// the cell was uninitialized. If the cell was uninitialized + /// and `f()` failed, an error is returned. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. Doing @@ -239,12 +242,12 @@ impl OnceCell { } /// Gets the mutable reference of the contents of the cell, initializing - /// it with `f` if the cell was empty. If the cell was empty and `f` failed, - /// an error is returned. + /// it to `f()` if the cell was uninitialized. If the cell was uninitialized + /// and `f()` failed, an error is returned. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// # Examples @@ -256,7 +259,7 @@ impl OnceCell { /// /// let mut cell: OnceCell = OnceCell::new(); /// - /// // Failed initializers do not change the value + /// // Failed attempts to initialize the cell do not change its contents /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err()); /// assert!(cell.get().is_none()); /// @@ -295,7 +298,7 @@ impl OnceCell { /// Consumes the cell, returning the wrapped value. /// - /// Returns `None` if the cell was empty. + /// Returns `None` if the cell was uninitialized. /// /// # Examples /// @@ -321,7 +324,7 @@ impl OnceCell { /// Takes the value out of this `OnceCell`, moving it back to an uninitialized state. /// - /// Has no effect and returns `None` if the `OnceCell` hasn't been initialized. + /// Has no effect and returns `None` if the `OnceCell` is uninitialized. /// /// Safety is guaranteed by requiring a mutable reference. /// diff --git a/library/std/src/sync/once_lock.rs b/library/std/src/sync/once_lock.rs index 6fc0abbed9e15..8f769f2dca37e 100644 --- a/library/std/src/sync/once_lock.rs +++ b/library/std/src/sync/once_lock.rs @@ -13,6 +13,9 @@ use crate::sync::Once; /// Where OnceLock shines is when LazyLock is too simple to support a given case, as LazyLock /// doesn't allow additional inputs to its function after you call [`LazyLock::new(|| ...)`]. /// +/// A `OnceLock` can be thought of as a safe abstraction over uninitialized data that becomes +/// initialized once written. +/// /// [`OnceCell`]: crate::cell::OnceCell /// [`LazyLock`]: crate::sync::LazyLock /// [`LazyLock::new(|| ...)`]: crate::sync::LazyLock::new @@ -126,7 +129,7 @@ pub struct OnceLock { } impl OnceLock { - /// Creates a new empty cell. + /// Creates a new uninitialized cell. #[inline] #[must_use] #[stable(feature = "once_cell", since = "1.70.0")] @@ -141,8 +144,8 @@ impl OnceLock { /// Gets the reference to the underlying value. /// - /// Returns `None` if the cell is empty, or being initialized. This - /// method never blocks. + /// Returns `None` if the cell is uninitialized, or being initialized. + /// This method never blocks. #[inline] #[stable(feature = "once_cell", since = "1.70.0")] pub fn get(&self) -> Option<&T> { @@ -156,7 +159,8 @@ impl OnceLock { /// Gets the mutable reference to the underlying value. /// - /// Returns `None` if the cell is empty. This method never blocks. + /// Returns `None` if the cell is uninitialized, or being initialized. + /// This method never blocks. #[inline] #[stable(feature = "once_cell", since = "1.70.0")] pub fn get_mut(&mut self) -> Option<&mut T> { @@ -194,12 +198,13 @@ impl OnceLock { unsafe { self.get_unchecked() } } - /// Sets the contents of this cell to `value`. + /// Initializes the contents of the cell to `value`. /// /// May block if another thread is currently attempting to initialize the cell. The cell is - /// guaranteed to contain a value when set returns, though not necessarily the one provided. + /// guaranteed to contain a value when `set` returns, though not necessarily the one provided. /// - /// Returns `Ok(())` if the cell's value was set by this call. + /// Returns `Ok(())` if the cell was uninitialized and + /// `Err(value)` if the cell was already initialized. /// /// # Examples /// @@ -228,13 +233,15 @@ impl OnceLock { } } - /// Sets the contents of this cell to `value` if the cell was empty, then - /// returns a reference to it. + /// Initializes the contents of the cell to `value` if the cell was uninitialized, + /// then returns a reference to it. /// /// May block if another thread is currently attempting to initialize the cell. The cell is - /// guaranteed to contain a value when set returns, though not necessarily the one provided. + /// guaranteed to contain a value when `try_insert` returns, though not necessarily the + /// one provided. /// - /// Returns `Ok(&value)` if the cell was empty and `Err(¤t_value, value)` if it was full. + /// Returns `Ok(&value)` if the cell was uninitialized and + /// `Err((¤t_value, value))` if it was already initialized. /// /// # Examples /// @@ -267,8 +274,8 @@ impl OnceLock { } } - /// Gets the contents of the cell, initializing it with `f` if the cell - /// was empty. + /// Gets the contents of the cell, initializing it to `f()` if the cell + /// was uninitialized. /// /// Many threads may call `get_or_init` concurrently with different /// initializing functions, but it is guaranteed that only one function @@ -276,7 +283,7 @@ impl OnceLock { /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. The @@ -306,13 +313,13 @@ impl OnceLock { } /// Gets the mutable reference of the contents of the cell, initializing - /// it with `f` if the cell was empty. + /// it to `f()` if the cell was uninitialized. /// /// This method never blocks. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and the cell + /// If `f()` panics, the panic is propagated to the caller, and the cell /// remains uninitialized. /// /// # Examples @@ -343,13 +350,13 @@ impl OnceLock { } } - /// Gets the contents of the cell, initializing it with `f` if - /// the cell was empty. If the cell was empty and `f` failed, an - /// error is returned. + /// Gets the contents of the cell, initializing it to `f()` if + /// the cell was uninitialized. If the cell was uninitialized + /// and `f()` failed, an error is returned. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and + /// If `f()` panics, the panic is propagated to the caller, and /// the cell remains uninitialized. /// /// It is an error to reentrantly initialize the cell from `f`. @@ -395,14 +402,14 @@ impl OnceLock { } /// Gets the mutable reference of the contents of the cell, initializing - /// it with `f` if the cell was empty. If the cell was empty and `f` failed, - /// an error is returned. + /// it to `f()` if the cell was uninitialized. If the cell was uninitialized + /// and `f()` failed, an error is returned. /// /// This method never blocks. /// /// # Panics /// - /// If `f` panics, the panic is propagated to the caller, and + /// If `f()` panics, the panic is propagated to the caller, and /// the cell remains uninitialized. /// /// # Examples @@ -414,7 +421,7 @@ impl OnceLock { /// /// let mut cell: OnceLock = OnceLock::new(); /// - /// // Failed initializers do not change the value + /// // Failed attempts to initialize the cell do not change its contents /// assert!(cell.get_mut_or_try_init(|| "not a number!".parse()).is_err()); /// assert!(cell.get().is_none()); /// @@ -438,7 +445,7 @@ impl OnceLock { } /// Consumes the `OnceLock`, returning the wrapped value. Returns - /// `None` if the cell was empty. + /// `None` if the cell was uninitialized. /// /// # Examples /// @@ -460,7 +467,7 @@ impl OnceLock { /// Takes the value out of this `OnceLock`, moving it back to an uninitialized state. /// - /// Has no effect and returns `None` if the `OnceLock` hasn't been initialized. + /// Has no effect and returns `None` if the `OnceLock` was uninitialized. /// /// Safety is guaranteed by requiring a mutable reference. /// @@ -526,7 +533,7 @@ impl OnceLock { /// # Safety /// - /// The value must be initialized + /// The cell must be initialized #[inline] unsafe fn get_unchecked(&self) -> &T { debug_assert!(self.is_initialized()); @@ -535,7 +542,7 @@ impl OnceLock { /// # Safety /// - /// The value must be initialized + /// The cell must be initialized #[inline] unsafe fn get_unchecked_mut(&mut self) -> &mut T { debug_assert!(self.is_initialized()); @@ -560,7 +567,7 @@ impl UnwindSafe for OnceLock {} #[stable(feature = "once_cell", since = "1.70.0")] impl Default for OnceLock { - /// Creates a new empty cell. + /// Creates a new uninitialized cell. /// /// # Example /// diff --git a/src/doc/book b/src/doc/book index fa312a343fbff..e2fa4316c5a7c 160000 --- a/src/doc/book +++ b/src/doc/book @@ -1 +1 @@ -Subproject commit fa312a343fbff01bc6cef393e326817f70719813 +Subproject commit e2fa4316c5a7c0d2499c5d6b799adcfad6ef7a45 diff --git a/src/doc/edition-guide b/src/doc/edition-guide index 4ed5a1a4a2a7e..f56aecc3b036d 160000 --- a/src/doc/edition-guide +++ b/src/doc/edition-guide @@ -1 +1 @@ -Subproject commit 4ed5a1a4a2a7ecc2e529a5baaef04f7bc7917eda +Subproject commit f56aecc3b036dff16404b525a83b00f911b9bbea diff --git a/src/doc/nomicon b/src/doc/nomicon index bc22988655446..336f75835a6c0 160000 --- a/src/doc/nomicon +++ b/src/doc/nomicon @@ -1 +1 @@ -Subproject commit bc2298865544695c63454fc1f9f98a3dc22e9948 +Subproject commit 336f75835a6c0514852cc65aba9a698b699b13c8 diff --git a/src/doc/reference b/src/doc/reference index 93b921c7d3213..4249fb411dd27 160000 --- a/src/doc/reference +++ b/src/doc/reference @@ -1 +1 @@ -Subproject commit 93b921c7d3213d38d920f7f905a3bec093d2217d +Subproject commit 4249fb411dd27f945e2881eb0378044b94cee06f diff --git a/src/doc/rust-by-example b/src/doc/rust-by-example index 054259ed1bf01..743766929f1e5 160000 --- a/src/doc/rust-by-example +++ b/src/doc/rust-by-example @@ -1 +1 @@ -Subproject commit 054259ed1bf01cdee4309ee764c7e103f6df3de5 +Subproject commit 743766929f1e53e72fab74394ae259bbfb4a7619 diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index 8227dfa043e3a..3b6abdd84832c 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -34,9 +34,9 @@ target | notes -------|------- [`aarch64-apple-darwin`](platform-support/apple-darwin.md) | ARM64 macOS (11.0+, Big Sur+) `aarch64-unknown-linux-gnu` | ARM64 Linux (kernel 4.1, glibc 2.17+) -`i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI] -`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+) [^x86_32-floats-return-ABI] -`i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+) [^x86_32-floats-return-ABI] +`i686-pc-windows-gnu` | 32-bit MinGW (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] +`i686-pc-windows-msvc` | 32-bit MSVC (Windows 10+, Windows Server 2016+, Pentium 4) [^x86_32-floats-return-ABI] +`i686-unknown-linux-gnu` | 32-bit Linux (kernel 3.2+, glibc 2.17+, Pentium 4) [^x86_32-floats-return-ABI] [`x86_64-apple-darwin`](platform-support/apple-darwin.md) | 64-bit macOS (10.12+, Sierra+) `x86_64-pc-windows-gnu` | 64-bit MinGW (Windows 10+, Windows Server 2016+) `x86_64-pc-windows-msvc` | 64-bit MSVC (Windows 10+, Windows Server 2016+) @@ -162,14 +162,14 @@ target | std | notes [`armv7a-none-eabi`](platform-support/arm-none-eabi.md) | * | Bare Armv7-A [`armv7r-none-eabi`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R [`armv7r-none-eabihf`](platform-support/armv7r-none-eabi.md) | * | Bare Armv7-R, hardfloat -`i586-pc-windows-msvc` | * | 32-bit Windows w/o SSE [^x86_32-floats-x87] -`i586-unknown-linux-gnu` | ✓ | 32-bit Linux w/o SSE (kernel 3.2, glibc 2.17) [^x86_32-floats-x87] -`i586-unknown-linux-musl` | ✓ | 32-bit Linux w/o SSE, musl 1.2.3 [^x86_32-floats-x87] -[`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android [^x86_32-floats-return-ABI] -[`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+), LLVM ABI [^x86_32-floats-return-ABI] -[`i686-unknown-freebsd`](platform-support/freebsd.md) | ✓ | 32-bit x86 FreeBSD [^x86_32-floats-return-ABI] -`i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 [^x86_32-floats-return-ABI] -[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? | 32-bit UEFI +`i586-pc-windows-msvc` | * | 32-bit Windows (original Pentium) [^x86_32-floats-x87] +`i586-unknown-linux-gnu` | ✓ | 32-bit Linux (kernel 3.2, glibc 2.17, original Pentium) [^x86_32-floats-x87] +`i586-unknown-linux-musl` | ✓ | 32-bit Linux (musl 1.2.3, original Pentium) [^x86_32-floats-x87] +[`i686-linux-android`](platform-support/android.md) | ✓ | 32-bit x86 Android ([PentiumPro with SSE](https://developer.android.com/ndk/guides/abis.html#x86)) [^x86_32-floats-return-ABI] +[`i686-pc-windows-gnullvm`](platform-support/pc-windows-gnullvm.md) | ✓ | 32-bit x86 MinGW (Windows 10+, Pentium 4), LLVM ABI [^x86_32-floats-return-ABI] +[`i686-unknown-freebsd`](platform-support/freebsd.md) | ✓ | 32-bit x86 FreeBSD (Pentium 4) [^x86_32-floats-return-ABI] +`i686-unknown-linux-musl` | ✓ | 32-bit Linux with musl 1.2.3 (Pentium 4) [^x86_32-floats-return-ABI] +[`i686-unknown-uefi`](platform-support/unknown-uefi.md) | ? (Pentium 4, softfloat) | 32-bit UEFI [`loongarch64-unknown-none`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64D ABI) [`loongarch64-unknown-none-softfloat`](platform-support/loongarch-none.md) | * | LoongArch64 Bare-metal (LP64S ABI) [`nvptx64-nvidia-cuda`](platform-support/nvptx64-nvidia-cuda.md) | * | --emit=asm generates PTX code that [runs on NVIDIA GPUs] @@ -307,15 +307,15 @@ target | std | host | notes `csky-unknown-linux-gnuabiv2hf` | ✓ | | C-SKY abiv2 Linux, hardfloat (little endian) [`hexagon-unknown-linux-musl`](platform-support/hexagon-unknown-linux-musl.md) | ✓ | | Hexagon Linux with musl 1.2.3 [`hexagon-unknown-none-elf`](platform-support/hexagon-unknown-none-elf.md)| * | | Bare Hexagon (v60+, HVX) -[`i386-apple-ios`](platform-support/apple-ios.md) | ✓ | | 32-bit x86 iOS [^x86_32-floats-return-ABI] -[`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS [^x86_32-floats-return-ABI] -[`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ | | 32-bit x86, restricted to Pentium -[`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+) [^x86_32-floats-return-ABI] -`i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku [^x86_32-floats-return-ABI] -[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd [^x86_32-floats-return-ABI] -[`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 with SSE2 [^x86_32-floats-return-ABI] -[`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD [^x86_32-floats-return-ABI] -[`i686-unknown-redox`](platform-support/redox.md) | ✓ | | i686 Redox OS +[`i386-apple-ios`](platform-support/apple-ios.md) | ✓ | | 32-bit x86 iOS (Penryn) [^x86_32-floats-return-ABI] +[`i586-pc-nto-qnx700`](platform-support/nto-qnx.md) | * | | 32-bit x86 QNX Neutrino 7.0 RTOS (Pentium 4) [^x86_32-floats-return-ABI] +[`i586-unknown-netbsd`](platform-support/netbsd.md) | ✓ | | 32-bit x86 (original Pentium) [^x86_32-floats-x87] +[`i686-apple-darwin`](platform-support/apple-darwin.md) | ✓ | ✓ | 32-bit macOS (10.12+, Sierra+, Penryn) [^x86_32-floats-return-ABI] +`i686-unknown-haiku` | ✓ | ✓ | 32-bit Haiku (Pentium 4) [^x86_32-floats-return-ABI] +[`i686-unknown-hurd-gnu`](platform-support/hurd.md) | ✓ | ✓ | 32-bit GNU/Hurd (PentiumPro) [^x86_32-floats-x87] +[`i686-unknown-netbsd`](platform-support/netbsd.md) | ✓ | ✓ | NetBSD/i386 (Pentium 4) [^x86_32-floats-return-ABI] +[`i686-unknown-openbsd`](platform-support/openbsd.md) | ✓ | ✓ | 32-bit OpenBSD (Pentium 4) [^x86_32-floats-return-ABI] +[`i686-unknown-redox`](platform-support/redox.md) | ✓ | | i686 Redox OS (PentiumPro) [^x86_32-floats-x87] `i686-uwp-windows-gnu` | ✓ | | [^x86_32-floats-return-ABI] [`i686-uwp-windows-msvc`](platform-support/uwp-windows-msvc.md) | ✓ | | [^x86_32-floats-return-ABI] [`i686-win7-windows-gnu`](platform-support/win7-windows-gnu.md) | ✓ | | 32-bit Windows 7 support [^x86_32-floats-return-ABI] diff --git a/src/librustdoc/clean/mod.rs b/src/librustdoc/clean/mod.rs index 7853e311a040c..0d4ff6e7aa57f 100644 --- a/src/librustdoc/clean/mod.rs +++ b/src/librustdoc/clean/mod.rs @@ -1104,17 +1104,29 @@ fn clean_args_from_types_and_names<'tcx>( types: &[hir::Ty<'tcx>], names: &[Ident], ) -> Arguments { + fn nonempty_name(ident: &Ident) -> Option { + if ident.name == kw::Underscore || ident.name == kw::Empty { + None + } else { + Some(ident.name) + } + } + + // If at least one argument has a name, use `_` as the name of unnamed + // arguments. Otherwise omit argument names. + let default_name = if names.iter().any(|ident| nonempty_name(ident).is_some()) { + kw::Underscore + } else { + kw::Empty + }; + Arguments { values: types .iter() .enumerate() .map(|(i, ty)| Argument { type_: clean_ty(ty, cx), - name: names - .get(i) - .map(|ident| ident.name) - .filter(|ident| !ident.is_empty()) - .unwrap_or(kw::Underscore), + name: names.get(i).and_then(nonempty_name).unwrap_or(default_name), is_const: false, }) .collect(), diff --git a/src/librustdoc/html/format.rs b/src/librustdoc/html/format.rs index 20a8dc724914f..ffd457c82737c 100644 --- a/src/librustdoc/html/format.rs +++ b/src/librustdoc/html/format.rs @@ -1408,7 +1408,9 @@ impl clean::Arguments { ) -> impl Display + 'a + Captures<'tcx> { fmt::from_fn(move |f| { for (i, input) in self.values.iter().enumerate() { - write!(f, "{}: ", input.name)?; + if !input.name.is_empty() { + write!(f, "{}: ", input.name)?; + } input.type_.print(cx).fmt(f)?; if i + 1 < self.values.len() { write!(f, ", ")?; diff --git a/src/tools/tidy/src/issues.txt b/src/tools/tidy/src/issues.txt index 839d23fb9a78c..17786ed6d2fdb 100644 --- a/src/tools/tidy/src/issues.txt +++ b/src/tools/tidy/src/issues.txt @@ -3146,7 +3146,6 @@ ui/nll/issue-97997.rs ui/nll/issue-98170.rs ui/nll/issue-98589-closures-relate-named-regions.rs ui/nll/issue-98693.rs -ui/nll/polonius/issue-46589.rs ui/nll/relate_tys/issue-48071.rs ui/nll/ty-outlives/issue-53789-1.rs ui/nll/ty-outlives/issue-53789-2.rs diff --git a/tests/rustdoc/assoc-consts.rs b/tests/rustdoc/assoc-consts.rs index cb8e839541c3b..247b5b180a869 100644 --- a/tests/rustdoc/assoc-consts.rs +++ b/tests/rustdoc/assoc-consts.rs @@ -45,7 +45,7 @@ pub fn f(_: &(ToString + 'static)) {} impl Bar { //@ has assoc_consts/struct.Bar.html '//*[@id="associatedconstant.F"]' \ - // "const F: fn(_: &(dyn ToString + 'static))" + // "const F: fn(&(dyn ToString + 'static))" pub const F: fn(_: &(ToString + 'static)) = f; } diff --git a/tests/rustdoc/fn-pointer-arg-name.rs b/tests/rustdoc/fn-pointer-arg-name.rs index 3bde6e9ecfa8c..0ee1964511a1d 100644 --- a/tests/rustdoc/fn-pointer-arg-name.rs +++ b/tests/rustdoc/fn-pointer-arg-name.rs @@ -3,3 +3,11 @@ //@ has foo/fn.f.html //@ has - '//pre[@class="rust item-decl"]' 'pub fn f(callback: fn(len: usize, foo: u32))' pub fn f(callback: fn(len: usize, foo: u32)) {} + +//@ has foo/fn.g.html +//@ has - '//pre[@class="rust item-decl"]' 'pub fn g(_: fn(usize, u32))' +pub fn g(_: fn(usize, _: u32)) {} + +//@ has foo/fn.mixed.html +//@ has - '//pre[@class="rust item-decl"]' 'pub fn mixed(_: fn(_: usize, foo: u32))' +pub fn mixed(_: fn(usize, foo: u32)) {} diff --git a/tests/rustdoc/inherent-projections.rs b/tests/rustdoc/inherent-projections.rs index 4fc769f70f55c..ced4db9a490c8 100644 --- a/tests/rustdoc/inherent-projections.rs +++ b/tests/rustdoc/inherent-projections.rs @@ -13,7 +13,7 @@ impl Owner { } // Make sure we handle bound vars correctly. -//@ has 'inherent_projections/fn.user.html' '//pre[@class="rust item-decl"]' "user(_: for<'a> fn(_: Carrier<'a>::Focus))" +//@ has 'inherent_projections/fn.user.html' '//pre[@class="rust item-decl"]' "user(_: for<'a> fn(Carrier<'a>::Focus))" pub fn user(_: for<'a> fn(Carrier<'a>::Focus)) {} pub struct Carrier<'a>(&'a ()); diff --git a/tests/rustdoc/macro-higher-kinded-function.rs b/tests/rustdoc/macro-higher-kinded-function.rs index f14125d13091c..738ea8fb3f153 100644 --- a/tests/rustdoc/macro-higher-kinded-function.rs +++ b/tests/rustdoc/macro-higher-kinded-function.rs @@ -11,10 +11,10 @@ macro_rules! gen { } //@ has 'foo/struct.Providers.html' -//@ has - '//*[@class="rust item-decl"]//code' "pub a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8," -//@ has - '//*[@class="rust item-decl"]//code' "pub b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16," -//@ has - '//*[@id="structfield.a"]/code' "a: for<'tcx> fn(_: TyCtxt<'tcx>, _: u8) -> i8" -//@ has - '//*[@id="structfield.b"]/code' "b: for<'tcx> fn(_: TyCtxt<'tcx>, _: u16) -> i16" +//@ has - '//*[@class="rust item-decl"]//code' "pub a: for<'tcx> fn(TyCtxt<'tcx>, u8) -> i8," +//@ has - '//*[@class="rust item-decl"]//code' "pub b: for<'tcx> fn(TyCtxt<'tcx>, u16) -> i16," +//@ has - '//*[@id="structfield.a"]/code' "a: for<'tcx> fn(TyCtxt<'tcx>, u8) -> i8" +//@ has - '//*[@id="structfield.b"]/code' "b: for<'tcx> fn(TyCtxt<'tcx>, u16) -> i16" gen! { (a, 'tcx, [u8], [i8]) (b, 'tcx, [u16], [i16]) diff --git a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs index d7c7b2e24143a..1c838a9e5e199 100644 --- a/tests/ui/lifetimes/tail-expr-lock-poisoning.rs +++ b/tests/ui/lifetimes/tail-expr-lock-poisoning.rs @@ -1,5 +1,4 @@ //@ revisions: edition2021 edition2024 -//@ ignore-wasm no panic support //@ needs-subprocess //@ [edition2024] edition: 2024 //@ run-pass diff --git a/tests/ui/nll/get_default.legacy.stderr b/tests/ui/nll/get_default.legacy.stderr new file mode 100644 index 0000000000000..699250312dc6b --- /dev/null +++ b/tests/ui/nll/get_default.legacy.stderr @@ -0,0 +1,18 @@ +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable + --> $DIR/get_default.rs:35:17 + | +LL | fn err(map: &mut Map) -> &String { + | - let's call the lifetime of this reference `'1` +LL | loop { +LL | match map.get() { + | --- immutable borrow occurs here +LL | Some(v) => { +LL | map.set(String::new()); // We always expect an error here. + | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | return v; + | - returning this value requires that `*map` is borrowed for `'1` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/nll/get_default.stderr b/tests/ui/nll/get_default.nll.stderr similarity index 87% rename from tests/ui/nll/get_default.stderr rename to tests/ui/nll/get_default.nll.stderr index af79771e7e1b9..9b5976ca7170e 100644 --- a/tests/ui/nll/get_default.stderr +++ b/tests/ui/nll/get_default.nll.stderr @@ -1,5 +1,5 @@ error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable - --> $DIR/get_default.rs:21:17 + --> $DIR/get_default.rs:24:17 | LL | fn ok(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` @@ -14,7 +14,7 @@ LL | map.set(String::new()); // Ideally, this would not error. | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable - --> $DIR/get_default.rs:32:17 + --> $DIR/get_default.rs:35:17 | LL | fn err(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` @@ -22,14 +22,14 @@ LL | loop { LL | match map.get() { | --- immutable borrow occurs here LL | Some(v) => { -LL | map.set(String::new()); // Both AST and MIR error here +LL | map.set(String::new()); // We always expect an error here. | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here LL | LL | return v; | - returning this value requires that `*map` is borrowed for `'1` error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable - --> $DIR/get_default.rs:37:17 + --> $DIR/get_default.rs:40:17 | LL | fn err(map: &mut Map) -> &String { | - let's call the lifetime of this reference `'1` @@ -40,7 +40,7 @@ LL | match map.get() { LL | return v; | - returning this value requires that `*map` is borrowed for `'1` ... -LL | map.set(String::new()); // Ideally, just AST would error here +LL | map.set(String::new()); // Ideally, this would not error. | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here error: aborting due to 3 previous errors diff --git a/tests/ui/nll/get_default.polonius.stderr b/tests/ui/nll/get_default.polonius.stderr new file mode 100644 index 0000000000000..699250312dc6b --- /dev/null +++ b/tests/ui/nll/get_default.polonius.stderr @@ -0,0 +1,18 @@ +error[E0502]: cannot borrow `*map` as mutable because it is also borrowed as immutable + --> $DIR/get_default.rs:35:17 + | +LL | fn err(map: &mut Map) -> &String { + | - let's call the lifetime of this reference `'1` +LL | loop { +LL | match map.get() { + | --- immutable borrow occurs here +LL | Some(v) => { +LL | map.set(String::new()); // We always expect an error here. + | ^^^^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here +LL | +LL | return v; + | - returning this value requires that `*map` is borrowed for `'1` + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0502`. diff --git a/tests/ui/nll/get_default.rs b/tests/ui/nll/get_default.rs index ffac8a33da104..c3c09e9c2c553 100644 --- a/tests/ui/nll/get_default.rs +++ b/tests/ui/nll/get_default.rs @@ -1,7 +1,10 @@ // Basic test for free regions in the NLL code. This test ought to -// report an error due to a reborrowing constraint. Right now, we get -// a variety of errors from the older, AST-based machinery (notably -// borrowck), and then we get the NLL error at the end. +// report an error due to a reborrowing constraint. + +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: nll polonius legacy +//@ [polonius] compile-flags: -Z polonius=next +//@ [legacy] compile-flags: -Z polonius=legacy struct Map { } @@ -19,7 +22,7 @@ fn ok(map: &mut Map) -> &String { } None => { map.set(String::new()); // Ideally, this would not error. - //~^ ERROR borrowed as immutable + //[nll]~^ ERROR borrowed as immutable } } } @@ -29,13 +32,13 @@ fn err(map: &mut Map) -> &String { loop { match map.get() { Some(v) => { - map.set(String::new()); // Both AST and MIR error here + map.set(String::new()); // We always expect an error here. //~^ ERROR borrowed as immutable return v; } None => { - map.set(String::new()); // Ideally, just AST would error here - //~^ ERROR borrowed as immutable + map.set(String::new()); // Ideally, this would not error. + //[nll]~^ ERROR borrowed as immutable } } } diff --git a/tests/ui/nll/issue-46589.stderr b/tests/ui/nll/issue-46589.nll.stderr similarity index 94% rename from tests/ui/nll/issue-46589.stderr rename to tests/ui/nll/issue-46589.nll.stderr index abf62aaa51088..dc80c1d08deca 100644 --- a/tests/ui/nll/issue-46589.stderr +++ b/tests/ui/nll/issue-46589.nll.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `**other` as mutable more than once at a time - --> $DIR/issue-46589.rs:23:21 + --> $DIR/issue-46589.rs:24:21 | LL | *other = match (*other).get_self() { | -------- first mutable borrow occurs here diff --git a/tests/ui/nll/issue-46589.rs b/tests/ui/nll/issue-46589.rs index 417d9cab657a1..10aff0d7b4ef9 100644 --- a/tests/ui/nll/issue-46589.rs +++ b/tests/ui/nll/issue-46589.rs @@ -1,8 +1,9 @@ -// This tests passes in Polonius mode, so is skipped in the automated compare-mode. -// We will manually check it passes in Polonius tests, as we can't have a test here -// which conditionally passes depending on a test revision/compile-flags. - -//@ ignore-compare-mode-polonius +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: nll polonius_next polonius +//@ [polonius_next] check-pass +//@ [polonius_next] compile-flags: -Zpolonius=next +//@ [polonius] check-pass +//@ [polonius] compile-flags: -Zpolonius struct Foo; @@ -21,7 +22,7 @@ impl Foo { *other = match (*other).get_self() { Some(s) => s, None => (*other).new_self() - //~^ ERROR cannot borrow `**other` as mutable more than once at a time [E0499] + //[nll]~^ ERROR cannot borrow `**other` as mutable more than once at a time [E0499] }; let c = other; diff --git a/tests/ui/nll/polonius/assignment-kills-loans.rs b/tests/ui/nll/polonius/assignment-kills-loans.rs index 182262e5c4b9b..56ea9c2f1f937 100644 --- a/tests/ui/nll/polonius/assignment-kills-loans.rs +++ b/tests/ui/nll/polonius/assignment-kills-loans.rs @@ -4,8 +4,11 @@ // facts only on simple assignments, but not projections, incorrectly causing errors to be emitted // for code accepted by NLL. They are all variations from example code in the NLL RFC. +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: polonius_next polonius //@ check-pass -//@ compile-flags: -Z polonius +//@ [polonius_next] compile-flags: -Z polonius=next +//@ [polonius] compile-flags: -Z polonius struct List { value: T, diff --git a/tests/ui/nll/polonius/assignment-to-differing-field.stderr b/tests/ui/nll/polonius/assignment-to-differing-field.legacy.stderr similarity index 92% rename from tests/ui/nll/polonius/assignment-to-differing-field.stderr rename to tests/ui/nll/polonius/assignment-to-differing-field.legacy.stderr index c46d010e4f576..cf5594dbd0786 100644 --- a/tests/ui/nll/polonius/assignment-to-differing-field.stderr +++ b/tests/ui/nll/polonius/assignment-to-differing-field.legacy.stderr @@ -1,5 +1,5 @@ error[E0499]: cannot borrow `list.0.value` as mutable more than once at a time - --> $DIR/assignment-to-differing-field.rs:20:21 + --> $DIR/assignment-to-differing-field.rs:23:21 | LL | fn assignment_to_field_projection<'a, T>( | -- lifetime `'a` defined here @@ -11,7 +11,7 @@ LL | return result; | ------ returning this value requires that `list.0.value` is borrowed for `'a` error[E0499]: cannot borrow `list.0.next` as mutable more than once at a time - --> $DIR/assignment-to-differing-field.rs:23:26 + --> $DIR/assignment-to-differing-field.rs:26:26 | LL | fn assignment_to_field_projection<'a, T>( | -- lifetime `'a` defined here @@ -23,7 +23,7 @@ LL | list.1 = n; | ---------- assignment requires that `list.0.next` is borrowed for `'a` error[E0499]: cannot borrow `list.0.0.0.0.0.value` as mutable more than once at a time - --> $DIR/assignment-to-differing-field.rs:37:21 + --> $DIR/assignment-to-differing-field.rs:40:21 | LL | fn assignment_through_projection_chain<'a, T>( | -- lifetime `'a` defined here @@ -35,7 +35,7 @@ LL | return result; | ------ returning this value requires that `list.0.0.0.0.0.value` is borrowed for `'a` error[E0499]: cannot borrow `list.0.0.0.0.0.next` as mutable more than once at a time - --> $DIR/assignment-to-differing-field.rs:40:26 + --> $DIR/assignment-to-differing-field.rs:43:26 | LL | fn assignment_through_projection_chain<'a, T>( | -- lifetime `'a` defined here diff --git a/tests/ui/nll/polonius/assignment-to-differing-field.polonius.stderr b/tests/ui/nll/polonius/assignment-to-differing-field.polonius.stderr new file mode 100644 index 0000000000000..cf5594dbd0786 --- /dev/null +++ b/tests/ui/nll/polonius/assignment-to-differing-field.polonius.stderr @@ -0,0 +1,51 @@ +error[E0499]: cannot borrow `list.0.value` as mutable more than once at a time + --> $DIR/assignment-to-differing-field.rs:23:21 + | +LL | fn assignment_to_field_projection<'a, T>( + | -- lifetime `'a` defined here +... +LL | result.push(&mut (list.0).value); + | ^^^^^^^^^^^^^^^^^^^ `list.0.value` was mutably borrowed here in the previous iteration of the loop +... +LL | return result; + | ------ returning this value requires that `list.0.value` is borrowed for `'a` + +error[E0499]: cannot borrow `list.0.next` as mutable more than once at a time + --> $DIR/assignment-to-differing-field.rs:26:26 + | +LL | fn assignment_to_field_projection<'a, T>( + | -- lifetime `'a` defined here +... +LL | if let Some(n) = (list.0).next.as_mut() { + | ^^^^^^^^^^^^^ `list.0.next` was mutably borrowed here in the previous iteration of the loop +LL | +LL | list.1 = n; + | ---------- assignment requires that `list.0.next` is borrowed for `'a` + +error[E0499]: cannot borrow `list.0.0.0.0.0.value` as mutable more than once at a time + --> $DIR/assignment-to-differing-field.rs:40:21 + | +LL | fn assignment_through_projection_chain<'a, T>( + | -- lifetime `'a` defined here +... +LL | result.push(&mut ((((list.0).0).0).0).0.value); + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ `list.0.0.0.0.0.value` was mutably borrowed here in the previous iteration of the loop +... +LL | return result; + | ------ returning this value requires that `list.0.0.0.0.0.value` is borrowed for `'a` + +error[E0499]: cannot borrow `list.0.0.0.0.0.next` as mutable more than once at a time + --> $DIR/assignment-to-differing-field.rs:43:26 + | +LL | fn assignment_through_projection_chain<'a, T>( + | -- lifetime `'a` defined here +... +LL | if let Some(n) = ((((list.0).0).0).0).0.next.as_mut() { + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ `list.0.0.0.0.0.next` was mutably borrowed here in the previous iteration of the loop +LL | +LL | *((((list.0).0).0).0).1 = n; + | --------------------------- assignment requires that `list.0.0.0.0.0.next` is borrowed for `'a` + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0499`. diff --git a/tests/ui/nll/polonius/assignment-to-differing-field.rs b/tests/ui/nll/polonius/assignment-to-differing-field.rs index fb6c956952543..9701cd2bb5e21 100644 --- a/tests/ui/nll/polonius/assignment-to-differing-field.rs +++ b/tests/ui/nll/polonius/assignment-to-differing-field.rs @@ -4,7 +4,10 @@ // that we do not kill too many borrows. Assignments to the `.1` // field projections should leave the borrows on `.0` intact. -//@ compile-flags: -Z polonius +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: polonius legacy +//@ [polonius] compile-flags: -Z polonius=next +//@ [legacy] compile-flags: -Z polonius=legacy struct List { value: T, diff --git a/tests/ui/nll/polonius/call-kills-loans.rs b/tests/ui/nll/polonius/call-kills-loans.rs index c02293c9a78aa..0657c42f48cda 100644 --- a/tests/ui/nll/polonius/call-kills-loans.rs +++ b/tests/ui/nll/polonius/call-kills-loans.rs @@ -4,8 +4,11 @@ // by NLL but was incorrectly rejected by Polonius because of these // missing `killed` facts. +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: polonius_next polonius //@ check-pass -//@ compile-flags: -Z polonius +//@ [polonius_next] compile-flags: -Z polonius=next +//@ [polonius] compile-flags: -Z polonius struct Thing; diff --git a/tests/ui/nll/polonius/issue-46589.rs b/tests/ui/nll/polonius/issue-46589.rs deleted file mode 100644 index af791f7e24ddd..0000000000000 --- a/tests/ui/nll/polonius/issue-46589.rs +++ /dev/null @@ -1,31 +0,0 @@ -// This test is a copy of `ui/nll/issue-46589.rs` which fails in NLL but succeeds in Polonius. -// As we can't have a test here which conditionally passes depending on a test -// revision/compile-flags. We ensure here that it passes in Polonius mode. - -//@ check-pass -//@ compile-flags: -Z polonius - -struct Foo; - -impl Foo { - fn get_self(&mut self) -> Option<&mut Self> { - Some(self) - } - - fn new_self(&mut self) -> &mut Self { - self - } - - fn trigger_bug(&mut self) { - let other = &mut (&mut *self); - - *other = match (*other).get_self() { - Some(s) => s, - None => (*other).new_self() - }; - - let c = other; - } -} - -fn main() {} diff --git a/tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs b/tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs index cb56c8f6deb4c..677b7aa1df860 100644 --- a/tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs +++ b/tests/ui/nll/polonius/location-insensitive-scopes-liveness.rs @@ -5,9 +5,11 @@ // than `liveness::trace`, on some specific CFGs shapes: a variable was dead during tracing but its // regions were marked live later, and live loans were not recomputed at this point. +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: polonius_next polonius //@ check-pass -//@ revisions: nll polonius -//@ [polonius] compile-flags: -Zpolonius=next +//@ [polonius_next] compile-flags: -Z polonius=next +//@ [polonius] compile-flags: -Z polonius // minimized from wavefc-cli-3.0.0 fn repro1() { diff --git a/tests/ui/nll/polonius/polonius-smoke-test.stderr b/tests/ui/nll/polonius/polonius-smoke-test.legacy.stderr similarity index 91% rename from tests/ui/nll/polonius/polonius-smoke-test.stderr rename to tests/ui/nll/polonius/polonius-smoke-test.legacy.stderr index a8a8267290def..1268f6167f855 100644 --- a/tests/ui/nll/polonius/polonius-smoke-test.stderr +++ b/tests/ui/nll/polonius/polonius-smoke-test.legacy.stderr @@ -1,11 +1,11 @@ error[E0515]: cannot return reference to local variable `x` - --> $DIR/polonius-smoke-test.rs:6:5 + --> $DIR/polonius-smoke-test.rs:10:5 | LL | &x | ^^ returns a reference to data owned by the current function error[E0503]: cannot use `x` because it was mutably borrowed - --> $DIR/polonius-smoke-test.rs:12:13 + --> $DIR/polonius-smoke-test.rs:16:13 | LL | let y = &mut x; | ------ `x` is borrowed here @@ -15,7 +15,7 @@ LL | let w = y; | - borrow later used here error[E0505]: cannot move out of `x` because it is borrowed - --> $DIR/polonius-smoke-test.rs:18:13 + --> $DIR/polonius-smoke-test.rs:22:13 | LL | pub fn use_while_mut_fr(x: &mut i32) -> &mut i32 { | - - let's call the lifetime of this reference `'1` @@ -35,7 +35,7 @@ LL + let y = &mut x.clone(); | error[E0505]: cannot move out of `s` because it is borrowed - --> $DIR/polonius-smoke-test.rs:42:5 + --> $DIR/polonius-smoke-test.rs:46:5 | LL | let s = &mut 1; | - binding `s` declared here diff --git a/tests/ui/nll/polonius/polonius-smoke-test.polonius.stderr b/tests/ui/nll/polonius/polonius-smoke-test.polonius.stderr new file mode 100644 index 0000000000000..1268f6167f855 --- /dev/null +++ b/tests/ui/nll/polonius/polonius-smoke-test.polonius.stderr @@ -0,0 +1,59 @@ +error[E0515]: cannot return reference to local variable `x` + --> $DIR/polonius-smoke-test.rs:10:5 + | +LL | &x + | ^^ returns a reference to data owned by the current function + +error[E0503]: cannot use `x` because it was mutably borrowed + --> $DIR/polonius-smoke-test.rs:16:13 + | +LL | let y = &mut x; + | ------ `x` is borrowed here +LL | let z = x; + | ^ use of borrowed `x` +LL | let w = y; + | - borrow later used here + +error[E0505]: cannot move out of `x` because it is borrowed + --> $DIR/polonius-smoke-test.rs:22:13 + | +LL | pub fn use_while_mut_fr(x: &mut i32) -> &mut i32 { + | - - let's call the lifetime of this reference `'1` + | | + | binding `x` declared here +LL | let y = &mut *x; + | ------- borrow of `*x` occurs here +LL | let z = x; + | ^ move out of `x` occurs here +LL | y + | - returning this value requires that `*x` is borrowed for `'1` + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let y = &mut *x; +LL + let y = &mut x.clone(); + | + +error[E0505]: cannot move out of `s` because it is borrowed + --> $DIR/polonius-smoke-test.rs:46:5 + | +LL | let s = &mut 1; + | - binding `s` declared here +LL | let r = &mut *s; + | ------- borrow of `*s` occurs here +LL | let tmp = foo(&r); +LL | s; + | ^ move out of `s` occurs here +LL | tmp; + | --- borrow later used here + | +help: consider cloning the value if the performance cost is acceptable + | +LL - let r = &mut *s; +LL + let r = &mut s.clone(); + | + +error: aborting due to 4 previous errors + +Some errors have detailed explanations: E0503, E0505, E0515. +For more information about an error, try `rustc --explain E0503`. diff --git a/tests/ui/nll/polonius/polonius-smoke-test.rs b/tests/ui/nll/polonius/polonius-smoke-test.rs index ea5cdb263f5dd..7fbb3f9b47c3b 100644 --- a/tests/ui/nll/polonius/polonius-smoke-test.rs +++ b/tests/ui/nll/polonius/polonius-smoke-test.rs @@ -1,5 +1,9 @@ -// Check that Polonius borrow check works for simple cases. -//@ compile-flags: -Z polonius +// Check that Polonius works for simple cases. + +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: polonius legacy +//@ [polonius] compile-flags: -Z polonius=next +//@ [legacy] compile-flags: -Z polonius=legacy pub fn return_ref_to_local() -> &'static i32 { let x = 0; diff --git a/tests/ui/nll/polonius/storagedead-kills-loans.rs b/tests/ui/nll/polonius/storagedead-kills-loans.rs index 89cf919bb48e0..75a37e6ece575 100644 --- a/tests/ui/nll/polonius/storagedead-kills-loans.rs +++ b/tests/ui/nll/polonius/storagedead-kills-loans.rs @@ -3,8 +3,11 @@ // is correctly accepted by NLL but was incorrectly rejected by // Polonius because of these missing `killed` facts. +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: polonius_next polonius //@ check-pass -//@ compile-flags: -Z polonius +//@ [polonius_next] compile-flags: -Z polonius=next +//@ [polonius] compile-flags: -Z polonius use std::{io, mem}; use std::io::Read; diff --git a/tests/ui/nll/polonius/subset-relations.stderr b/tests/ui/nll/polonius/subset-relations.legacy.stderr similarity index 92% rename from tests/ui/nll/polonius/subset-relations.stderr rename to tests/ui/nll/polonius/subset-relations.legacy.stderr index 9deca6449a8f1..10d42ca58d9df 100644 --- a/tests/ui/nll/polonius/subset-relations.stderr +++ b/tests/ui/nll/polonius/subset-relations.legacy.stderr @@ -1,5 +1,5 @@ error: lifetime may not live long enough - --> $DIR/subset-relations.rs:10:5 + --> $DIR/subset-relations.rs:13:5 | LL | fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 { | -- -- lifetime `'b` defined here diff --git a/tests/ui/nll/polonius/subset-relations.polonius.stderr b/tests/ui/nll/polonius/subset-relations.polonius.stderr new file mode 100644 index 0000000000000..10d42ca58d9df --- /dev/null +++ b/tests/ui/nll/polonius/subset-relations.polonius.stderr @@ -0,0 +1,14 @@ +error: lifetime may not live long enough + --> $DIR/subset-relations.rs:13:5 + | +LL | fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 { + | -- -- lifetime `'b` defined here + | | + | lifetime `'a` defined here +LL | y + | ^ function was supposed to return data with lifetime `'a` but it is returning data with lifetime `'b` + | + = help: consider adding the following bound: `'b: 'a` + +error: aborting due to 1 previous error + diff --git a/tests/ui/nll/polonius/subset-relations.rs b/tests/ui/nll/polonius/subset-relations.rs index 3c1af1983cfd0..d47e4e05533ee 100644 --- a/tests/ui/nll/polonius/subset-relations.rs +++ b/tests/ui/nll/polonius/subset-relations.rs @@ -3,7 +3,10 @@ // two free regions outlive each other, without any evidence that this // relation holds. -//@ compile-flags: -Z polonius +//@ ignore-compare-mode-polonius (explicit revisions) +//@ revisions: polonius legacy +//@ [polonius] compile-flags: -Z polonius=next +//@ [legacy] compile-flags: -Z polonius=legacy // returning `y` requires that `'b: 'a`, but it's not known to be true fn missing_subset<'a, 'b>(x: &'a u32, y: &'b u32) -> &'a u32 { @@ -22,7 +25,7 @@ fn implied_bounds_subset<'a, 'b>(x: &'a &'b mut u32) -> &'a u32 { // `'b: 'a` is declared, and `'a: 'c` is known via implied bounds: // `'b: 'c` is therefore known to hold transitively -fn transitively_valid_subset<'a, 'b: 'a, 'c>(x: &'c &'a u32, y: &'b u32) -> &'c u32 { +fn transitively_valid_subset<'a, 'b: 'a, 'c>(x: &'c &'a u32, y: &'b u32) -> &'c u32 { y } diff --git a/tests/ui/panics/issue-47429-short-backtraces.rs b/tests/ui/panics/issue-47429-short-backtraces.rs index 4a73ebe8712dc..378ade67bfd08 100644 --- a/tests/ui/panics/issue-47429-short-backtraces.rs +++ b/tests/ui/panics/issue-47429-short-backtraces.rs @@ -17,8 +17,6 @@ //@ ignore-msvc see #62897 and `backtrace-debuginfo.rs` test //@ ignore-android FIXME #17520 //@ ignore-openbsd no support for libbacktrace without filename -//@ ignore-wasm no panic support -//@ ignore-emscripten no panic support //@ ignore-fuchsia Backtraces not symbolized //@ needs-subprocess diff --git a/tests/ui/panics/issue-47429-short-backtraces.run.stderr b/tests/ui/panics/issue-47429-short-backtraces.run.stderr index c6e2d13fb5da7..32dc6592271de 100644 --- a/tests/ui/panics/issue-47429-short-backtraces.run.stderr +++ b/tests/ui/panics/issue-47429-short-backtraces.run.stderr @@ -1,5 +1,5 @@ -thread 'main' panicked at $DIR/issue-47429-short-backtraces.rs:26:5: +thread 'main' panicked at $DIR/issue-47429-short-backtraces.rs:24:5: explicit panic stack backtrace: 0: std::panicking::begin_panic diff --git a/tests/ui/panics/runtime-switch.rs b/tests/ui/panics/runtime-switch.rs index 9f0be8c7ddfa6..7d5b416934078 100644 --- a/tests/ui/panics/runtime-switch.rs +++ b/tests/ui/panics/runtime-switch.rs @@ -18,7 +18,6 @@ //@ ignore-android FIXME #17520 //@ ignore-openbsd no support for libbacktrace without filename //@ ignore-wasm no backtrace support -//@ ignore-emscripten no panic support //@ ignore-fuchsia Backtrace not symbolized //@ needs-subprocess diff --git a/tests/ui/panics/runtime-switch.run.stderr b/tests/ui/panics/runtime-switch.run.stderr index 458a0ee534a96..70ed127af8643 100644 --- a/tests/ui/panics/runtime-switch.run.stderr +++ b/tests/ui/panics/runtime-switch.run.stderr @@ -1,5 +1,5 @@ -thread 'main' panicked at $DIR/runtime-switch.rs:29:5: +thread 'main' panicked at $DIR/runtime-switch.rs:28:5: explicit panic stack backtrace: 0: std::panicking::begin_panic diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.rs b/tests/ui/panics/short-ice-remove-middle-frames-2.rs index 48f60b141706b..660530f0eada8 100644 --- a/tests/ui/panics/short-ice-remove-middle-frames-2.rs +++ b/tests/ui/panics/short-ice-remove-middle-frames-2.rs @@ -5,7 +5,6 @@ //@ needs-unwind //@ ignore-android FIXME #17520 //@ ignore-openbsd no support for libbacktrace without filename -//@ ignore-emscripten no panic //@ ignore-sgx Backtraces not symbolized //@ ignore-fuchsia Backtraces not symbolized //@ ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable. diff --git a/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr index 1fddcca69510d..664d51e185dd5 100644 --- a/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr +++ b/tests/ui/panics/short-ice-remove-middle-frames-2.run.stderr @@ -1,5 +1,5 @@ -thread 'main' panicked at $DIR/short-ice-remove-middle-frames-2.rs:63:5: +thread 'main' panicked at $DIR/short-ice-remove-middle-frames-2.rs:62:5: debug!!! stack backtrace: 0: std::panicking::begin_panic diff --git a/tests/ui/panics/short-ice-remove-middle-frames.rs b/tests/ui/panics/short-ice-remove-middle-frames.rs index 216c512779956..41fb6e9950e6c 100644 --- a/tests/ui/panics/short-ice-remove-middle-frames.rs +++ b/tests/ui/panics/short-ice-remove-middle-frames.rs @@ -5,7 +5,6 @@ //@ needs-unwind //@ ignore-android FIXME #17520 //@ ignore-openbsd no support for libbacktrace without filename -//@ ignore-emscripten no panic //@ ignore-sgx Backtraces not symbolized //@ ignore-fuchsia Backtraces not symbolized //@ ignore-msvc the `__rust_{begin,end}_short_backtrace` symbols aren't reliable. diff --git a/tests/ui/panics/short-ice-remove-middle-frames.run.stderr b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr index 630b09d8d1ec6..e966462331fcf 100644 --- a/tests/ui/panics/short-ice-remove-middle-frames.run.stderr +++ b/tests/ui/panics/short-ice-remove-middle-frames.run.stderr @@ -1,5 +1,5 @@ -thread 'main' panicked at $DIR/short-ice-remove-middle-frames.rs:59:5: +thread 'main' panicked at $DIR/short-ice-remove-middle-frames.rs:58:5: debug!!! stack backtrace: 0: std::panicking::begin_panic diff --git a/tests/ui/test-attrs/test-panic-abort-disabled.rs b/tests/ui/test-attrs/test-panic-abort-disabled.rs index 05dd9395c2b06..e83be65f9250c 100644 --- a/tests/ui/test-attrs/test-panic-abort-disabled.rs +++ b/tests/ui/test-attrs/test-panic-abort-disabled.rs @@ -4,8 +4,6 @@ //@ run-flags: --test-threads=1 //@ needs-unwind -//@ ignore-wasm no panic support -//@ ignore-emscripten no panic support //@ needs-subprocess #![cfg(test)] diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.rs b/tests/ui/test-attrs/test-panic-abort-nocapture.rs index f7e15dbdbc30c..6a1025ea087c0 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.rs +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.rs @@ -7,8 +7,6 @@ //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ ignore-android #120567 -//@ ignore-wasm no panic support -//@ ignore-emscripten no panic support //@ needs-subprocess #![cfg(test)] diff --git a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr index 256811711703b..b9f267838b191 100644 --- a/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr +++ b/tests/ui/test-attrs/test-panic-abort-nocapture.run.stderr @@ -1,11 +1,11 @@ -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:34:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:32:5: assertion `left == right` failed left: 2 right: 4 note: run with `RUST_BACKTRACE=1` environment variable to display a backtrace -thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:28:5: +thread 'main' panicked at $DIR/test-panic-abort-nocapture.rs:26:5: assertion `left == right` failed left: 2 right: 4 diff --git a/tests/ui/test-attrs/test-panic-abort.rs b/tests/ui/test-attrs/test-panic-abort.rs index 951cf54346b4f..6c9b641fb6fba 100644 --- a/tests/ui/test-attrs/test-panic-abort.rs +++ b/tests/ui/test-attrs/test-panic-abort.rs @@ -7,8 +7,6 @@ //@ normalize-stdout: "finished in \d+\.\d+s" -> "finished in $$TIME" //@ ignore-android #120567 -//@ ignore-wasm no panic support -//@ ignore-emscripten no panic support //@ needs-subprocess #![cfg(test)] diff --git a/tests/ui/test-attrs/test-panic-abort.run.stdout b/tests/ui/test-attrs/test-panic-abort.run.stdout index 844808e86370d..0faa7f0dfcec4 100644 --- a/tests/ui/test-attrs/test-panic-abort.run.stdout +++ b/tests/ui/test-attrs/test-panic-abort.run.stdout @@ -18,7 +18,7 @@ testing123 ---- it_fails stderr ---- testing321 -thread 'main' panicked at $DIR/test-panic-abort.rs:39:5: +thread 'main' panicked at $DIR/test-panic-abort.rs:37:5: assertion `left == right` failed left: 2 right: 5