From 4e5fe71ca65020642361c4d3b3a3c2401864d5a4 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 13 Nov 2023 14:39:32 +0000 Subject: [PATCH 01/93] stop referring to a region as a "row" in liveness values --- .../rustc_borrowck/src/region_infer/values.rs | 34 +++++++++---------- 1 file changed, 17 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 38452df32e9e..bedf130a866b 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -138,34 +138,34 @@ impl LivenessValues { /// Adds the given element to the value for the given region. Returns whether /// the element is newly added (i.e., was not already present). - pub(crate) fn add_element(&mut self, row: N, location: Location) -> bool { - debug!("LivenessValues::add(r={:?}, location={:?})", row, location); + pub(crate) fn add_element(&mut self, region: N, location: Location) -> bool { + debug!("LivenessValues::add_element(region={:?}, location={:?})", region, location); let index = self.elements.point_from_location(location); - self.points.insert(row, index) + self.points.insert(region, index) } /// Adds all the elements in the given bit array into the given /// region. Returns whether any of them are newly added. - pub(crate) fn add_elements(&mut self, row: N, locations: &IntervalSet) -> bool { - debug!("LivenessValues::add_elements(row={:?}, locations={:?})", row, locations); - self.points.union_row(row, locations) + pub(crate) fn add_elements(&mut self, region: N, locations: &IntervalSet) -> bool { + debug!("LivenessValues::add_elements(region={:?}, locations={:?})", region, locations); + self.points.union_row(region, locations) } - /// Adds all the control-flow points to the values for `r`. - pub(crate) fn add_all_points(&mut self, row: N) { - self.points.insert_all_into_row(row); + /// Records `region` as being live at all the control-flow points. + pub(crate) fn add_all_points(&mut self, region: N) { + self.points.insert_all_into_row(region); } - /// Returns `true` if the region `r` contains the given element. - pub(crate) fn contains(&self, row: N, location: Location) -> bool { + /// Returns `true` if the region `region` contains the given element. + pub(crate) fn contains(&self, region: N, location: Location) -> bool { let index = self.elements.point_from_location(location); - self.points.row(row).is_some_and(|r| r.contains(index)) + self.points.row(region).is_some_and(|r| r.contains(index)) } - /// Returns an iterator of all the elements contained by the region `r` - pub(crate) fn get_elements(&self, row: N) -> impl Iterator + '_ { + /// Returns an iterator of all the elements contained by `region`. + pub(crate) fn get_elements(&self, region: N) -> impl Iterator + '_ { self.points - .row(row) + .row(region) .into_iter() .flat_map(|set| set.iter()) .take_while(move |&p| self.elements.point_in_range(p)) @@ -173,8 +173,8 @@ impl LivenessValues { } /// Returns a "pretty" string value of the region. Meant for debugging. - pub(crate) fn region_value_str(&self, r: N) -> String { - region_value_str(self.get_elements(r).map(RegionElement::Location)) + pub(crate) fn region_value_str(&self, region: N) -> String { + region_value_str(self.get_elements(region).map(RegionElement::Location)) } #[inline] From 3e3e7a023fa7b4d3ea11009565b09b1ec64c2b86 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 13 Nov 2023 14:44:17 +0000 Subject: [PATCH 02/93] iterate over regions and not "rows" in liveness values --- compiler/rustc_borrowck/src/region_infer/mod.rs | 2 +- compiler/rustc_borrowck/src/region_infer/values.rs | 2 +- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b1f91a056282..aeb9f935ecc1 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -359,7 +359,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { let mut scc_values = RegionValues::new(elements, universal_regions.len(), &placeholder_indices); - for region in liveness_constraints.rows() { + for region in liveness_constraints.regions() { let scc = constraint_sccs.scc(region); scc_values.merge_liveness(scc, region, &liveness_constraints); } diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index bedf130a866b..48bfd6bd1324 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -132,7 +132,7 @@ impl LivenessValues { } /// Iterate through each region that has a value in this set. - pub(crate) fn rows(&self) -> impl Iterator { + pub(crate) fn regions(&self) -> impl Iterator { self.points.rows() } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 608d010394f6..96c23cfaf77d 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -592,7 +592,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { } self.cx.borrowck_context.constraints.outlives_constraints.push(constraint) } - for region in liveness_constraints.rows() { + for region in liveness_constraints.regions() { // If the region is live at at least one location in the promoted MIR, // then add a liveness constraint to the main MIR for this region // at the location provided as an argument to this method From fb94626431e2637306aede1095cb66e6bbb43777 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 13 Nov 2023 14:49:16 +0000 Subject: [PATCH 03/93] add locations instead of "element"s, and remove unused return value --- compiler/rustc_borrowck/src/constraint_generation.rs | 2 +- compiler/rustc_borrowck/src/region_infer/values.rs | 11 +++++------ compiler/rustc_borrowck/src/type_check/mod.rs | 6 +++--- 3 files changed, 9 insertions(+), 10 deletions(-) diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index 1f642099f089..02b3bed94bfc 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -167,7 +167,7 @@ impl<'cx, 'tcx> ConstraintGeneration<'cx, 'tcx> { self.infcx.tcx.for_each_free_region(&live_ty, |live_region| { let vid = live_region.as_var(); - self.liveness_constraints.add_element(vid, location); + self.liveness_constraints.add_location(vid, location); }); } diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 48bfd6bd1324..03630f0e2bcb 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -136,12 +136,11 @@ impl LivenessValues { self.points.rows() } - /// Adds the given element to the value for the given region. Returns whether - /// the element is newly added (i.e., was not already present). - pub(crate) fn add_element(&mut self, region: N, location: Location) -> bool { - debug!("LivenessValues::add_element(region={:?}, location={:?})", region, location); - let index = self.elements.point_from_location(location); - self.points.insert(region, index) + /// Records `region` as being live at the given `location`. + pub(crate) fn add_location(&mut self, region: N, location: Location) { + debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location); + let point = self.elements.point_from_location(location); + self.points.insert(region, point); } /// Adds all the elements in the given bit array into the given diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index 96c23cfaf77d..f00e41e08863 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -318,7 +318,7 @@ impl<'a, 'b, 'tcx> Visitor<'tcx> for TypeVerifier<'a, 'b, 'tcx> { .borrowck_context .constraints .liveness_constraints - .add_element(live_region_vid, location); + .add_location(live_region_vid, location); }); // HACK(compiler-errors): Constants that are gathered into Body.required_consts @@ -601,7 +601,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { .borrowck_context .constraints .liveness_constraints - .add_element(region, location); + .add_location(region, location); } } } @@ -1443,7 +1443,7 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { self.borrowck_context .constraints .liveness_constraints - .add_element(region_vid, term_location); + .add_location(region_vid, term_location); } self.check_call_inputs(body, term, func, &sig, args, term_location, *call_source); From c8feeb6ced8b934fea40d5d4e99527e6bb6e8368 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 13 Nov 2023 14:54:07 +0000 Subject: [PATCH 04/93] refer to points and not "elements", and remove unused return value --- compiler/rustc_borrowck/src/region_infer/values.rs | 9 ++++----- compiler/rustc_borrowck/src/type_check/liveness/trace.rs | 2 +- 2 files changed, 5 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 03630f0e2bcb..2e15dee0c81f 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -143,11 +143,10 @@ impl LivenessValues { self.points.insert(region, point); } - /// Adds all the elements in the given bit array into the given - /// region. Returns whether any of them are newly added. - pub(crate) fn add_elements(&mut self, region: N, locations: &IntervalSet) -> bool { - debug!("LivenessValues::add_elements(region={:?}, locations={:?})", region, locations); - self.points.union_row(region, locations) + /// Records `region` as being live at all the given `points`. + pub(crate) fn add_points(&mut self, region: N, points: &IntervalSet) { + debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points); + self.points.union_row(region, points); } /// Records `region` as being live at all the control-flow points. diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index e616449ccd41..2cfbe8a38746 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -618,7 +618,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { .borrowck_context .constraints .liveness_constraints - .add_elements(live_region_vid, live_at); + .add_points(live_region_vid, live_at); // There can only be inflowing loans for this region when we are using // `-Zpolonius=next`. From 23bc9c6a624b2a8a517f597341e8277c6dce85e8 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 13 Nov 2023 14:58:16 +0000 Subject: [PATCH 05/93] regions do not contain liveness elements --- compiler/rustc_borrowck/src/region_infer/mod.rs | 8 ++++---- compiler/rustc_borrowck/src/region_infer/values.rs | 8 ++++---- 2 files changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index aeb9f935ecc1..b9a824c1401a 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1963,15 +1963,15 @@ impl<'tcx> RegionInferenceContext<'tcx> { None } - /// Finds some region R such that `fr1: R` and `R` is live at `elem`. + /// Finds some region R such that `fr1: R` and `R` is live at `location`. #[instrument(skip(self), level = "trace", ret)] - pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, elem: Location) -> RegionVid { + pub(crate) fn find_sub_region_live_at(&self, fr1: RegionVid, location: Location) -> RegionVid { trace!(scc = ?self.constraint_sccs.scc(fr1)); trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]); self.find_constraint_paths_between_regions(fr1, |r| { - // First look for some `r` such that `fr1: r` and `r` is live at `elem` + // First look for some `r` such that `fr1: r` and `r` is live at `location` trace!(?r, liveness_constraints=?self.liveness_constraints.region_value_str(r)); - self.liveness_constraints.contains(r, elem) + self.liveness_constraints.is_live_at(r, location) }) .or_else(|| { // If we fail to find that, we may find some `r` such that diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 2e15dee0c81f..14df7d0553bd 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -154,10 +154,10 @@ impl LivenessValues { self.points.insert_all_into_row(region); } - /// Returns `true` if the region `region` contains the given element. - pub(crate) fn contains(&self, region: N, location: Location) -> bool { - let index = self.elements.point_from_location(location); - self.points.row(region).is_some_and(|r| r.contains(index)) + /// Returns whether `region` is marked live at the given `location`. + pub(crate) fn is_live_at(&self, region: N, location: Location) -> bool { + let point = self.elements.point_from_location(location); + self.points.row(region).is_some_and(|r| r.contains(point)) } /// Returns an iterator of all the elements contained by `region`. From b4c7d1dd05ed839ab80d5fe0452d890743a7ae5b Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 13 Nov 2023 15:07:35 +0000 Subject: [PATCH 06/93] fix doc --- compiler/rustc_borrowck/src/region_infer/values.rs | 8 +++----- 1 file changed, 3 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 14df7d0553bd..502e884b531d 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -116,17 +116,15 @@ pub(crate) enum RegionElement { PlaceholderRegion(ty::PlaceholderRegion), } -/// When we initially compute liveness, we use an interval matrix storing -/// liveness ranges for each region-vid. +/// Records the CFG locations where each region is live. When we initially compute liveness, we use +/// an interval matrix storing liveness ranges for each region-vid. pub(crate) struct LivenessValues { elements: Rc, points: SparseIntervalMatrix, } impl LivenessValues { - /// Creates a new set of "region values" that tracks causal information. - /// Each of the regions in num_region_variables will be initialized with an - /// empty set of points and no causal information. + /// Create an empty map of regions to locations where they're live. pub(crate) fn new(elements: Rc) -> Self { Self { points: SparseIntervalMatrix::new(elements.num_points), elements } } From 79c5e913d3de11566cf60fa1d069141639ee913f Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 13 Nov 2023 15:18:47 +0000 Subject: [PATCH 07/93] introduce `is_live_anywhere` instead of peeking into points and refactor misnamed `get_elements` --- .../rustc_borrowck/src/region_infer/values.rs | 16 +++++++++++----- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- 2 files changed, 12 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index 502e884b531d..d0e24f7817ad 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -158,19 +158,25 @@ impl LivenessValues { self.points.row(region).is_some_and(|r| r.contains(point)) } - /// Returns an iterator of all the elements contained by `region`. - pub(crate) fn get_elements(&self, region: N) -> impl Iterator + '_ { + /// Returns whether `region` is marked live at any location. + pub(crate) fn is_live_anywhere(&self, region: N) -> bool { + self.live_points(region).next().is_some() + } + + /// Returns an iterator of all the points where `region` is live. + fn live_points(&self, region: N) -> impl Iterator + '_ { self.points .row(region) .into_iter() .flat_map(|set| set.iter()) - .take_while(move |&p| self.elements.point_in_range(p)) - .map(move |p| self.elements.to_location(p)) + .take_while(|&p| self.elements.point_in_range(p)) } /// Returns a "pretty" string value of the region. Meant for debugging. pub(crate) fn region_value_str(&self, region: N) -> String { - region_value_str(self.get_elements(region).map(RegionElement::Location)) + region_value_str( + self.live_points(region).map(|p| RegionElement::Location(self.elements.to_location(p))), + ) } #[inline] diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index f00e41e08863..e23f633bea2b 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -596,7 +596,7 @@ impl<'a, 'b, 'tcx> TypeVerifier<'a, 'b, 'tcx> { // If the region is live at at least one location in the promoted MIR, // then add a liveness constraint to the main MIR for this region // at the location provided as an argument to this method - if liveness_constraints.get_elements(region).next().is_some() { + if liveness_constraints.is_live_anywhere(region) { self.cx .borrowck_context .constraints From 84a002cc4299b387a5f4b234f50155f8ea3c900d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 13 Nov 2023 15:28:26 +0000 Subject: [PATCH 08/93] `LivenessValues` does not need to be generic over regions --- .../src/constraint_generation.rs | 6 ++--- .../rustc_borrowck/src/region_infer/mod.rs | 4 ++-- .../rustc_borrowck/src/region_infer/values.rs | 24 +++++++++---------- compiler/rustc_borrowck/src/type_check/mod.rs | 2 +- 4 files changed, 18 insertions(+), 18 deletions(-) diff --git a/compiler/rustc_borrowck/src/constraint_generation.rs b/compiler/rustc_borrowck/src/constraint_generation.rs index 02b3bed94bfc..21d367c40cb9 100644 --- a/compiler/rustc_borrowck/src/constraint_generation.rs +++ b/compiler/rustc_borrowck/src/constraint_generation.rs @@ -9,7 +9,7 @@ use rustc_middle::mir::{ }; use rustc_middle::ty::visit::TypeVisitable; use rustc_middle::ty::GenericArgsRef; -use rustc_middle::ty::{self, RegionVid, Ty, TyCtxt}; +use rustc_middle::ty::{self, Ty, TyCtxt}; use crate::{ borrow_set::BorrowSet, facts::AllFacts, location::LocationTable, places_conflict, @@ -18,7 +18,7 @@ use crate::{ pub(super) fn generate_constraints<'tcx>( infcx: &InferCtxt<'tcx>, - liveness_constraints: &mut LivenessValues, + liveness_constraints: &mut LivenessValues, all_facts: &mut Option, location_table: &LocationTable, body: &Body<'tcx>, @@ -43,7 +43,7 @@ struct ConstraintGeneration<'cg, 'tcx> { infcx: &'cg InferCtxt<'tcx>, all_facts: &'cg mut Option, location_table: &'cg LocationTable, - liveness_constraints: &'cg mut LivenessValues, + liveness_constraints: &'cg mut LivenessValues, borrow_set: &'cg BorrowSet<'tcx>, body: &'cg Body<'tcx>, } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index b9a824c1401a..ff125a027451 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -59,7 +59,7 @@ pub struct RegionInferenceContext<'tcx> { /// regions, these start out empty and steadily grow, though for /// each universally quantified region R they start out containing /// the entire CFG and `end(R)`. - liveness_constraints: LivenessValues, + liveness_constraints: LivenessValues, /// The outlives constraints computed by the type-check. constraints: Frozen>, @@ -332,7 +332,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { member_constraints_in: MemberConstraintSet<'tcx, RegionVid>, universe_causes: FxIndexMap>, type_tests: Vec>, - liveness_constraints: LivenessValues, + liveness_constraints: LivenessValues, elements: &Rc, live_loans: SparseBitMatrix, ) -> Self { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index d0e24f7817ad..e73872bf66ae 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -118,53 +118,53 @@ pub(crate) enum RegionElement { /// Records the CFG locations where each region is live. When we initially compute liveness, we use /// an interval matrix storing liveness ranges for each region-vid. -pub(crate) struct LivenessValues { +pub(crate) struct LivenessValues { elements: Rc, - points: SparseIntervalMatrix, + points: SparseIntervalMatrix, } -impl LivenessValues { +impl LivenessValues { /// Create an empty map of regions to locations where they're live. pub(crate) fn new(elements: Rc) -> Self { Self { points: SparseIntervalMatrix::new(elements.num_points), elements } } /// Iterate through each region that has a value in this set. - pub(crate) fn regions(&self) -> impl Iterator { + pub(crate) fn regions(&self) -> impl Iterator { self.points.rows() } /// Records `region` as being live at the given `location`. - pub(crate) fn add_location(&mut self, region: N, location: Location) { + pub(crate) fn add_location(&mut self, region: RegionVid, location: Location) { debug!("LivenessValues::add_location(region={:?}, location={:?})", region, location); let point = self.elements.point_from_location(location); self.points.insert(region, point); } /// Records `region` as being live at all the given `points`. - pub(crate) fn add_points(&mut self, region: N, points: &IntervalSet) { + pub(crate) fn add_points(&mut self, region: RegionVid, points: &IntervalSet) { debug!("LivenessValues::add_points(region={:?}, points={:?})", region, points); self.points.union_row(region, points); } /// Records `region` as being live at all the control-flow points. - pub(crate) fn add_all_points(&mut self, region: N) { + pub(crate) fn add_all_points(&mut self, region: RegionVid) { self.points.insert_all_into_row(region); } /// Returns whether `region` is marked live at the given `location`. - pub(crate) fn is_live_at(&self, region: N, location: Location) -> bool { + pub(crate) fn is_live_at(&self, region: RegionVid, location: Location) -> bool { let point = self.elements.point_from_location(location); self.points.row(region).is_some_and(|r| r.contains(point)) } /// Returns whether `region` is marked live at any location. - pub(crate) fn is_live_anywhere(&self, region: N) -> bool { + pub(crate) fn is_live_anywhere(&self, region: RegionVid) -> bool { self.live_points(region).next().is_some() } /// Returns an iterator of all the points where `region` is live. - fn live_points(&self, region: N) -> impl Iterator + '_ { + fn live_points(&self, region: RegionVid) -> impl Iterator + '_ { self.points .row(region) .into_iter() @@ -173,7 +173,7 @@ impl LivenessValues { } /// Returns a "pretty" string value of the region. Meant for debugging. - pub(crate) fn region_value_str(&self, region: N) -> String { + pub(crate) fn region_value_str(&self, region: RegionVid) -> String { region_value_str( self.live_points(region).map(|p| RegionElement::Location(self.elements.to_location(p))), ) @@ -309,7 +309,7 @@ impl RegionValues { /// `self[to] |= values[from]`, essentially: that is, take all the /// elements for the region `from` from `values` and add them to /// the region `to` in `self`. - pub(crate) fn merge_liveness(&mut self, to: N, from: M, values: &LivenessValues) { + pub(crate) fn merge_liveness(&mut self, to: N, from: RegionVid, values: &LivenessValues) { if let Some(set) = values.points.row(from) { self.points.union_row(to, set); } diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index e23f633bea2b..f0e35bdb75f5 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -899,7 +899,7 @@ pub(crate) struct MirTypeckRegionConstraints<'tcx> { /// not otherwise appear in the MIR -- in particular, the /// late-bound regions that it instantiates at call-sites -- and /// hence it must report on their liveness constraints. - pub(crate) liveness_constraints: LivenessValues, + pub(crate) liveness_constraints: LivenessValues, pub(crate) outlives_constraints: OutlivesConstraintSet<'tcx>, From d203476c4f25895205dfaeb11519339b2ecd1867 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?R=C3=A9my=20Rakic?= Date: Mon, 13 Nov 2023 15:35:04 +0000 Subject: [PATCH 09/93] rename debugging support functions --- .../rustc_borrowck/src/region_infer/dump_mir.rs | 2 +- compiler/rustc_borrowck/src/region_infer/mod.rs | 2 +- .../rustc_borrowck/src/region_infer/values.rs | 17 ++++++++++------- .../src/type_check/liveness/trace.rs | 4 ++-- 4 files changed, 14 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs index 4d620ac9de61..cfbb2766c339 100644 --- a/compiler/rustc_borrowck/src/region_infer/dump_mir.rs +++ b/compiler/rustc_borrowck/src/region_infer/dump_mir.rs @@ -67,7 +67,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { with_msg: &mut dyn FnMut(&str) -> io::Result<()>, ) -> io::Result<()> { for region in self.definitions.indices() { - let value = self.liveness_constraints.region_value_str(region); + let value = self.liveness_constraints.pretty_print_live_points(region); if value != "{}" { with_msg(&format!("{region:?} live at {value}"))?; } diff --git a/compiler/rustc_borrowck/src/region_infer/mod.rs b/compiler/rustc_borrowck/src/region_infer/mod.rs index ff125a027451..f25376c248fb 100644 --- a/compiler/rustc_borrowck/src/region_infer/mod.rs +++ b/compiler/rustc_borrowck/src/region_infer/mod.rs @@ -1970,7 +1970,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { trace!(universe = ?self.scc_universes[self.constraint_sccs.scc(fr1)]); self.find_constraint_paths_between_regions(fr1, |r| { // First look for some `r` such that `fr1: r` and `r` is live at `location` - trace!(?r, liveness_constraints=?self.liveness_constraints.region_value_str(r)); + trace!(?r, liveness_constraints=?self.liveness_constraints.pretty_print_live_points(r)); self.liveness_constraints.is_live_at(r, location) }) .or_else(|| { diff --git a/compiler/rustc_borrowck/src/region_infer/values.rs b/compiler/rustc_borrowck/src/region_infer/values.rs index e73872bf66ae..93f5fbd00396 100644 --- a/compiler/rustc_borrowck/src/region_infer/values.rs +++ b/compiler/rustc_borrowck/src/region_infer/values.rs @@ -172,9 +172,10 @@ impl LivenessValues { .take_while(|&p| self.elements.point_in_range(p)) } - /// Returns a "pretty" string value of the region. Meant for debugging. - pub(crate) fn region_value_str(&self, region: RegionVid) -> String { - region_value_str( + /// For debugging purposes, returns a pretty-printed string of the points where the `region` is + /// live. + pub(crate) fn pretty_print_live_points(&self, region: RegionVid) -> String { + pretty_print_region_elements( self.live_points(region).map(|p| RegionElement::Location(self.elements.to_location(p))), ) } @@ -378,7 +379,7 @@ impl RegionValues { /// Returns a "pretty" string value of the region. Meant for debugging. pub(crate) fn region_value_str(&self, r: N) -> String { - region_value_str(self.elements_contained_in(r)) + pretty_print_region_elements(self.elements_contained_in(r)) } } @@ -422,11 +423,12 @@ impl ToElementIndex for ty::PlaceholderRegion { } } -pub(crate) fn location_set_str( +/// For debugging purposes, returns a pretty-printed string of the given points. +pub(crate) fn pretty_print_points( elements: &RegionValueElements, points: impl IntoIterator, ) -> String { - region_value_str( + pretty_print_region_elements( points .into_iter() .take_while(|&p| elements.point_in_range(p)) @@ -435,7 +437,8 @@ pub(crate) fn location_set_str( ) } -fn region_value_str(elements: impl IntoIterator) -> String { +/// For debugging purposes, returns a pretty-printed string of the given region elements. +fn pretty_print_region_elements(elements: impl IntoIterator) -> String { let mut result = String::new(); result.push('{'); diff --git a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs index 2cfbe8a38746..2ef4cf676823 100644 --- a/compiler/rustc_borrowck/src/type_check/liveness/trace.rs +++ b/compiler/rustc_borrowck/src/type_check/liveness/trace.rs @@ -550,7 +550,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { dropped_local, dropped_ty, drop_locations, - values::location_set_str(self.elements, live_at.iter()), + values::pretty_print_points(self.elements, live_at.iter()), ); let drop_data = self.drop_data.entry(dropped_ty).or_insert_with({ @@ -599,7 +599,7 @@ impl<'tcx> LivenessContext<'_, '_, '_, 'tcx> { debug!("make_all_regions_live(value={:?})", value); debug!( "make_all_regions_live: live_at={}", - values::location_set_str(elements, live_at.iter()), + values::pretty_print_points(elements, live_at.iter()), ); // When using `-Zpolonius=next`, we want to record the loans that flow into this value's From 497c17a3906f26c184dc530b2211d4e737b210da Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Tue, 14 Nov 2023 18:31:28 -0500 Subject: [PATCH 10/93] Add check-cfg to cranelift --- build_system/tests.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/build_system/tests.rs b/build_system/tests.rs index 10736ff9a55c..ff71a567ed3a 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -457,6 +457,8 @@ impl<'a> TestRunner<'a> { cmd.arg("--target"); cmd.arg(&self.target_compiler.triple); cmd.arg("-Cpanic=abort"); + cmd.arg("--check-cfg=cfg(no_unstable_features)"); + cmd.arg("--check-cfg=cfg(jit)"); cmd.args(args); cmd } From 8d91d6662fe66ad9e5af290311e7452f18107711 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 16 Nov 2023 11:35:59 +0100 Subject: [PATCH 11/93] Stabilize ptr_addr_eq library feature --- library/alloc/src/lib.rs | 1 - library/core/src/ptr/mod.rs | 9 +++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/library/alloc/src/lib.rs b/library/alloc/src/lib.rs index d33c4418e1b7..1a97778eb6ea 100644 --- a/library/alloc/src/lib.rs +++ b/library/alloc/src/lib.rs @@ -140,7 +140,6 @@ #![feature(maybe_uninit_uninit_array)] #![feature(maybe_uninit_uninit_array_transpose)] #![feature(pattern)] -#![feature(ptr_addr_eq)] #![feature(ptr_internals)] #![feature(ptr_metadata)] #![feature(ptr_sub_ptr)] diff --git a/library/core/src/ptr/mod.rs b/library/core/src/ptr/mod.rs index 63e42a8784c6..d6efa72c37b7 100644 --- a/library/core/src/ptr/mod.rs +++ b/library/core/src/ptr/mod.rs @@ -1898,14 +1898,15 @@ pub fn eq(a: *const T, b: *const T) -> bool { /// # Examples /// /// ``` -/// #![feature(ptr_addr_eq)] +/// use std::ptr; /// /// let whole: &[i32; 3] = &[1, 2, 3]; /// let first: &i32 = &whole[0]; -/// assert!(std::ptr::addr_eq(whole, first)); -/// assert!(!std::ptr::eq::(whole, first)); +/// +/// assert!(ptr::addr_eq(whole, first)); +/// assert!(!ptr::eq::(whole, first)); /// ``` -#[unstable(feature = "ptr_addr_eq", issue = "116324")] +#[stable(feature = "ptr_addr_eq", since = "CURRENT_RUSTC_VERSION")] #[inline(always)] #[must_use = "pointer comparison produces a value"] pub fn addr_eq(p: *const T, q: *const U) -> bool { From dfc669b74c214ad5afeb94211ebe1fd70ac8d43a Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 16 Nov 2023 21:15:07 +0000 Subject: [PATCH 12/93] Merge commit 'def04540a4e2541b995195c752c751295606a388' into sync_cg_clif-2023-11-16 --- .github/workflows/abi-cafe.yml | 4 + .github/workflows/main.yml | 10 + .github/workflows/rustc.yml | 6 + Readme.md | 49 ++++- rust-toolchain | 2 +- scripts/rustup.sh | 2 +- scripts/setup_rust_fork.sh | 10 +- scripts/test_bootstrap.sh | 4 +- src/abi/mod.rs | 1 + src/base.rs | 2 +- src/constant.rs | 43 ++-- src/inline_asm.rs | 166 ++++++---------- src/intrinsics/llvm.rs | 2 + src/intrinsics/llvm_x86.rs | 348 ++++++++++++++++++++++++++++----- src/intrinsics/simd.rs | 14 +- 15 files changed, 472 insertions(+), 191 deletions(-) diff --git a/.github/workflows/abi-cafe.yml b/.github/workflows/abi-cafe.yml index 12aa69d3c795..bd3b051185b4 100644 --- a/.github/workflows/abi-cafe.yml +++ b/.github/workflows/abi-cafe.yml @@ -35,6 +35,10 @@ jobs: steps: - uses: actions/checkout@v3 + - name: CPU features + if: matrix.os == 'ubuntu-latest' + run: cat /proc/cpuinfo + - name: Cache cargo target dir uses: actions/cache@v3 with: diff --git a/.github/workflows/main.yml b/.github/workflows/main.yml index 47d9a3b93f72..05dc28d07453 100644 --- a/.github/workflows/main.yml +++ b/.github/workflows/main.yml @@ -66,6 +66,10 @@ jobs: steps: - uses: actions/checkout@v3 + - name: CPU features + if: matrix.os == 'ubuntu-latest' + run: cat /proc/cpuinfo + - name: Cache cargo target dir uses: actions/cache@v3 with: @@ -136,6 +140,9 @@ jobs: steps: - uses: actions/checkout@v3 + - name: CPU features + run: cat /proc/cpuinfo + - name: Prepare dependencies run: ./y.sh prepare @@ -159,6 +166,9 @@ jobs: steps: - uses: actions/checkout@v3 + - name: CPU features + run: cat /proc/cpuinfo + - name: Cache cargo target dir uses: actions/cache@v3 with: diff --git a/.github/workflows/rustc.yml b/.github/workflows/rustc.yml index b49dc3aff7aa..cb5dd51fee31 100644 --- a/.github/workflows/rustc.yml +++ b/.github/workflows/rustc.yml @@ -11,6 +11,9 @@ jobs: steps: - uses: actions/checkout@v3 + - name: CPU features + run: cat /proc/cpuinfo + - name: Cache cargo target dir uses: actions/cache@v3 with: @@ -31,6 +34,9 @@ jobs: steps: - uses: actions/checkout@v3 + - name: CPU features + run: cat /proc/cpuinfo + - name: Cache cargo target dir uses: actions/cache@v3 with: diff --git a/Readme.md b/Readme.md index 1a2b2bbc5881..ca6ecdf1d0e8 100644 --- a/Readme.md +++ b/Readme.md @@ -5,8 +5,48 @@ This has the potential to improve compilation times in debug mode. If your project doesn't use any of the things listed under "Not yet supported", it should work fine. If not please open an issue. +## Download using Rustup + +The Cranelift codegen backend is distributed in nightly builds on Linux and x86_64 macOS. If you want to +install it using Rustup, you can do that by running: + +```bash +$ rustup component add rustc-codegen-cranelift-preview --toolchain nightly +``` + +Once it is installed, you can enable it with one of the following approaches: +- `CARGO_PROFILE_DEV_CODEGEN_BACKEND=cranelift cargo +nightly build -Zcodegen-backend` +- `RUSTFLAGS="-Zcodegen-backend=cranelift" cargo +nightly build` +- Add the following to `.cargo/config.toml`: + ```toml + [unstable] + codegen-backend = true + + [profile.dev] + codegen-backend = "cranelift" + ``` +- Add the following to `Cargo.toml`: + ```toml + # This line needs to come before anything else in Cargo.toml + cargo-features = ["codegen-backend"] + + [profile.dev] + codegen-backend = "cranelift" + ``` + +## Precompiled builds + +You can also download a pre-built version from the [releases] page. +Extract the `dist` directory in the archive anywhere you want. +If you want to use `cargo clif build` instead of having to specify the full path to the `cargo-clif` executable, you can add the `bin` subdirectory of the extracted `dist` directory to your `PATH`. +(tutorial [for Windows](https://stackoverflow.com/a/44272417), and [for Linux/MacOS](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path/26059#26059)). + +[releases]: https://github.com/rust-lang/rustc_codegen_cranelift/releases/tag/dev + ## Building and testing +If you want to build the backend manually, you can download it from GitHub and build it yourself: + ```bash $ git clone https://github.com/rust-lang/rustc_codegen_cranelift $ cd rustc_codegen_cranelift @@ -22,15 +62,6 @@ $ ./test.sh For more docs on how to build and test see [build_system/usage.txt](build_system/usage.txt) or the help message of `./y.sh`. -## Precompiled builds - -Alternatively you can download a pre built version from the [releases] page. -Extract the `dist` directory in the archive anywhere you want. -If you want to use `cargo clif build` instead of having to specify the full path to the `cargo-clif` executable, you can add the `bin` subdirectory of the extracted `dist` directory to your `PATH`. -(tutorial [for Windows](https://stackoverflow.com/a/44272417), and [for Linux/MacOS](https://unix.stackexchange.com/questions/26047/how-to-correctly-add-a-path-to-path/26059#26059)). - -[releases]: https://github.com/rust-lang/rustc_codegen_cranelift/releases/tag/dev - ## Usage rustc_codegen_cranelift can be used as a near-drop-in replacement for `cargo build` or `cargo run` for existing projects. diff --git a/rust-toolchain b/rust-toolchain index b832b06e0ffb..80ef1e49f231 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-11-10" +channel = "nightly-2023-11-16" components = ["rust-src", "rustc-dev", "llvm-tools"] diff --git a/scripts/rustup.sh b/scripts/rustup.sh index e62788f2e507..355282911c25 100755 --- a/scripts/rustup.sh +++ b/scripts/rustup.sh @@ -46,7 +46,7 @@ case $1 in git pull origin master branch=sync_cg_clif-$(date +%Y-%m-%d) git checkout -b "$branch" - "$cg_clif/git-fixed-subtree.sh" pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/bjorn3/rustc_codegen_cranelift.git master + "$cg_clif/git-fixed-subtree.sh" pull --prefix=compiler/rustc_codegen_cranelift/ https://github.com/rust-lang/rustc_codegen_cranelift.git master git push -u my "$branch" # immediately merge the merge commit into cg_clif to prevent merge conflicts when syncing diff --git a/scripts/setup_rust_fork.sh b/scripts/setup_rust_fork.sh index bbb8a010d965..731828caae2c 100644 --- a/scripts/setup_rust_fork.sh +++ b/scripts/setup_rust_fork.sh @@ -1,15 +1,17 @@ #!/usr/bin/env bash set -e +# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we +# the LLVM backend isn't compiled in here. +export CG_CLIF_FORCE_GNU_AS=1 + # Compiletest expects all standard library paths to start with /rustc/FAKE_PREFIX. # CG_CLIF_STDLIB_REMAP_PATH_PREFIX will cause cg_clif's build system to pass # --remap-path-prefix to handle this. -# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we -# the LLVM backend isn't compiled in here. -CG_CLIF_FORCE_GNU_AS=1 CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build +CG_CLIF_STDLIB_REMAP_PATH_PREFIX=/rustc/FAKE_PREFIX ./y.sh build echo "[SETUP] Rust fork" -git clone https://github.com/rust-lang/rust.git || true +git clone https://github.com/rust-lang/rust.git --filter=tree:0 || true pushd rust git fetch git checkout -- . diff --git a/scripts/test_bootstrap.sh b/scripts/test_bootstrap.sh index a8f6d7a20248..791d457993de 100755 --- a/scripts/test_bootstrap.sh +++ b/scripts/test_bootstrap.sh @@ -11,7 +11,5 @@ rm -r compiler/rustc_codegen_cranelift/{Cargo.*,src} cp ../Cargo.* compiler/rustc_codegen_cranelift/ cp -r ../src compiler/rustc_codegen_cranelift/src -# CG_CLIF_FORCE_GNU_AS will force usage of as instead of the LLVM backend of rustc as we -# the LLVM backend isn't compiled in here. -CG_CLIF_FORCE_GNU_AS=1 ./x.py build --stage 1 library/std +./x.py build --stage 1 library/std popd diff --git a/src/abi/mod.rs b/src/abi/mod.rs index c4572e035258..0ff1473da431 100644 --- a/src/abi/mod.rs +++ b/src/abi/mod.rs @@ -383,6 +383,7 @@ pub(crate) fn codegen_terminator_call<'tcx>( args, ret_place, target, + source_info.span, ); return; } diff --git a/src/base.rs b/src/base.rs index 91b1547cb6ea..71557d49ef2c 100644 --- a/src/base.rs +++ b/src/base.rs @@ -456,7 +456,7 @@ fn codegen_fn_body(fx: &mut FunctionCx<'_, '_, '_>, start_block: Block) { ); } - crate::inline_asm::codegen_inline_asm( + crate::inline_asm::codegen_inline_asm_terminator( fx, source_info.span, template, diff --git a/src/constant.rs b/src/constant.rs index b0853d30e03b..cf68a3857c58 100644 --- a/src/constant.rs +++ b/src/constant.rs @@ -1,10 +1,13 @@ //! Handling of `static`s, `const`s and promoted allocations +use std::cmp::Ordering; + use cranelift_module::*; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_middle::middle::codegen_fn_attrs::CodegenFnAttrFlags; use rustc_middle::mir::interpret::{read_target_uint, AllocId, GlobalAlloc, Scalar}; use rustc_middle::mir::ConstValue; +use rustc_middle::ty::ScalarInt; use crate::prelude::*; @@ -430,9 +433,9 @@ fn define_all_allocs(tcx: TyCtxt<'_>, module: &mut dyn Module, cx: &mut Constant pub(crate) fn mir_operand_get_const_val<'tcx>( fx: &FunctionCx<'_, '_, 'tcx>, operand: &Operand<'tcx>, -) -> Option> { +) -> Option { match operand { - Operand::Constant(const_) => Some(eval_mir_constant(fx, const_).0), + Operand::Constant(const_) => eval_mir_constant(fx, const_).0.try_to_scalar_int(), // FIXME(rust-lang/rust#85105): Casts like `IMM8 as u32` result in the const being stored // inside a temporary before being passed to the intrinsic requiring the const argument. // This code tries to find a single constant defining definition of the referenced local. @@ -440,7 +443,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( if !place.projection.is_empty() { return None; } - let mut computed_const_val = None; + let mut computed_scalar_int = None; for bb_data in fx.mir.basic_blocks.iter() { for stmt in &bb_data.statements { match &stmt.kind { @@ -456,22 +459,38 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( operand, ty, ) => { - if computed_const_val.is_some() { + if computed_scalar_int.is_some() { return None; // local assigned twice } if !matches!(ty.kind(), ty::Uint(_) | ty::Int(_)) { return None; } - let const_val = mir_operand_get_const_val(fx, operand)?; - if fx.layout_of(*ty).size - != const_val.try_to_scalar_int()?.size() + let scalar_int = mir_operand_get_const_val(fx, operand)?; + let scalar_int = match fx + .layout_of(*ty) + .size + .cmp(&scalar_int.size()) { - return None; - } - computed_const_val = Some(const_val); + Ordering::Equal => scalar_int, + Ordering::Less => match ty.kind() { + ty::Uint(_) => ScalarInt::try_from_uint( + scalar_int.try_to_uint(scalar_int.size()).unwrap(), + fx.layout_of(*ty).size, + ) + .unwrap(), + ty::Int(_) => ScalarInt::try_from_int( + scalar_int.try_to_int(scalar_int.size()).unwrap(), + fx.layout_of(*ty).size, + ) + .unwrap(), + _ => unreachable!(), + }, + Ordering::Greater => return None, + }; + computed_scalar_int = Some(scalar_int); } Rvalue::Use(operand) => { - computed_const_val = mir_operand_get_const_val(fx, operand) + computed_scalar_int = mir_operand_get_const_val(fx, operand) } _ => return None, } @@ -522,7 +541,7 @@ pub(crate) fn mir_operand_get_const_val<'tcx>( TerminatorKind::Call { .. } => {} } } - computed_const_val + computed_scalar_int } } } diff --git a/src/inline_asm.rs b/src/inline_asm.rs index ce0eecca8a8b..25d14319f579 100644 --- a/src/inline_asm.rs +++ b/src/inline_asm.rs @@ -10,7 +10,7 @@ use target_lexicon::BinaryFormat; use crate::prelude::*; -enum CInlineAsmOperand<'tcx> { +pub(crate) enum CInlineAsmOperand<'tcx> { In { reg: InlineAsmRegOrRegClass, value: Value, @@ -34,7 +34,7 @@ enum CInlineAsmOperand<'tcx> { }, } -pub(crate) fn codegen_inline_asm<'tcx>( +pub(crate) fn codegen_inline_asm_terminator<'tcx>( fx: &mut FunctionCx<'_, '_, 'tcx>, span: Span, template: &[InlineAsmTemplatePiece], @@ -42,8 +42,6 @@ pub(crate) fn codegen_inline_asm<'tcx>( options: InlineAsmOptions, destination: Option, ) { - // FIXME add .eh_frame unwind info directives - // Used by panic_abort on Windows, but uses a syntax which only happens to work with // asm!() by accident and breaks with the GNU assembler as well as global_asm!() for // the LLVM backend. @@ -135,15 +133,33 @@ pub(crate) fn codegen_inline_asm<'tcx>( }) .collect::>(); - let mut inputs = Vec::new(); - let mut outputs = Vec::new(); + codegen_inline_asm_inner(fx, template, &operands, options); + + match destination { + Some(destination) => { + let destination_block = fx.get_block(destination); + fx.bcx.ins().jump(destination_block, &[]); + } + None => { + fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); + } + } +} + +pub(crate) fn codegen_inline_asm_inner<'tcx>( + fx: &mut FunctionCx<'_, '_, 'tcx>, + template: &[InlineAsmTemplatePiece], + operands: &[CInlineAsmOperand<'tcx>], + options: InlineAsmOptions, +) { + // FIXME add .eh_frame unwind info directives let mut asm_gen = InlineAssemblyGenerator { tcx: fx.tcx, arch: fx.tcx.sess.asm_arch.unwrap(), enclosing_def_id: fx.instance.def_id(), template, - operands: &operands, + operands, options, registers: Vec::new(), stack_slots_clobber: Vec::new(), @@ -165,6 +181,8 @@ pub(crate) fn codegen_inline_asm<'tcx>( let generated_asm = asm_gen.generate_asm_wrapper(&asm_name); fx.cx.global_asm.push_str(&generated_asm); + let mut inputs = Vec::new(); + let mut outputs = Vec::new(); for (i, operand) in operands.iter().enumerate() { match operand { CInlineAsmOperand::In { reg: _, value } => { @@ -186,16 +204,6 @@ pub(crate) fn codegen_inline_asm<'tcx>( } call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs); - - match destination { - Some(destination) => { - let destination_block = fx.get_block(destination); - fx.bcx.ins().jump(destination_block, &[]); - } - None => { - fx.bcx.ins().trap(TrapCode::UnreachableCodeReached); - } - } } struct InlineAssemblyGenerator<'a, 'tcx> { @@ -637,8 +645,21 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { ) { match arch { InlineAsmArch::X86_64 => { - write!(generated_asm, " mov [rbx+0x{:x}], ", offset.bytes()).unwrap(); - reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); + match reg { + InlineAsmReg::X86(reg) + if reg as u32 >= X86InlineAsmReg::xmm0 as u32 + && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + { + // rustc emits x0 rather than xmm0 + write!(generated_asm, " movups [rbx+0x{:x}], ", offset.bytes()).unwrap(); + write!(generated_asm, "xmm{}", reg as u32 - X86InlineAsmReg::xmm0 as u32) + .unwrap(); + } + _ => { + write!(generated_asm, " mov [rbx+0x{:x}], ", offset.bytes()).unwrap(); + reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); + } + } generated_asm.push('\n'); } InlineAsmArch::AArch64 => { @@ -663,8 +684,24 @@ impl<'tcx> InlineAssemblyGenerator<'_, 'tcx> { ) { match arch { InlineAsmArch::X86_64 => { - generated_asm.push_str(" mov "); - reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap(); + match reg { + InlineAsmReg::X86(reg) + if reg as u32 >= X86InlineAsmReg::xmm0 as u32 + && reg as u32 <= X86InlineAsmReg::xmm15 as u32 => + { + // rustc emits x0 rather than xmm0 + write!( + generated_asm, + " movups xmm{}", + reg as u32 - X86InlineAsmReg::xmm0 as u32 + ) + .unwrap(); + } + _ => { + generated_asm.push_str(" mov "); + reg.emit(generated_asm, InlineAsmArch::X86_64, None).unwrap() + } + } writeln!(generated_asm, ", [rbx+0x{:x}]", offset.bytes()).unwrap(); } InlineAsmArch::AArch64 => { @@ -720,7 +757,12 @@ fn call_inline_asm<'tcx>( fx.bcx.ins().call(inline_asm_func, &[stack_slot_addr]); for (offset, place) in outputs { - let ty = fx.clif_type(place.layout().ty).unwrap(); + let ty = if place.layout().ty.is_simd() { + let (lane_count, lane_type) = place.layout().ty.simd_size_and_type(fx.tcx); + fx.clif_type(lane_type).unwrap().by(lane_count.try_into().unwrap()).unwrap() + } else { + fx.clif_type(place.layout().ty).unwrap() + }; let value = stack_slot.offset(fx, i32::try_from(offset.bytes()).unwrap().into()).load( fx, ty, @@ -729,83 +771,3 @@ fn call_inline_asm<'tcx>( place.write_cvalue(fx, CValue::by_val(value, place.layout())); } } - -pub(crate) fn codegen_xgetbv<'tcx>( - fx: &mut FunctionCx<'_, '_, 'tcx>, - xcr_no: Value, - ret: CPlace<'tcx>, -) { - // FIXME add .eh_frame unwind info directives - - let operands = vec![ - CInlineAsmOperand::In { - reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)), - value: xcr_no, - }, - CInlineAsmOperand::Out { - reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)), - late: true, - place: Some(ret), - }, - CInlineAsmOperand::Out { - reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)), - late: true, - place: None, - }, - ]; - let options = InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM; - - let mut inputs = Vec::new(); - let mut outputs = Vec::new(); - - let mut asm_gen = InlineAssemblyGenerator { - tcx: fx.tcx, - arch: fx.tcx.sess.asm_arch.unwrap(), - enclosing_def_id: fx.instance.def_id(), - template: &[InlineAsmTemplatePiece::String( - " - xgetbv - // out = rdx << 32 | rax - shl rdx, 32 - or rax, rdx - " - .to_string(), - )], - operands: &operands, - options, - registers: Vec::new(), - stack_slots_clobber: Vec::new(), - stack_slots_input: Vec::new(), - stack_slots_output: Vec::new(), - stack_slot_size: Size::from_bytes(0), - }; - asm_gen.allocate_registers(); - asm_gen.allocate_stack_slots(); - - let inline_asm_index = fx.cx.inline_asm_index.get(); - fx.cx.inline_asm_index.set(inline_asm_index + 1); - let asm_name = format!( - "__inline_asm_{}_n{}", - fx.cx.cgu_name.as_str().replace('.', "__").replace('-', "_"), - inline_asm_index - ); - - let generated_asm = asm_gen.generate_asm_wrapper(&asm_name); - fx.cx.global_asm.push_str(&generated_asm); - - for (i, operand) in operands.iter().enumerate() { - match operand { - CInlineAsmOperand::In { reg: _, value } => { - inputs.push((asm_gen.stack_slots_input[i].unwrap(), *value)); - } - CInlineAsmOperand::Out { reg: _, late: _, place } => { - if let Some(place) = place { - outputs.push((asm_gen.stack_slots_output[i].unwrap(), *place)); - } - } - _ => unreachable!(), - } - } - - call_inline_asm(fx, &asm_name, asm_gen.stack_slot_size, inputs, outputs); -} diff --git a/src/intrinsics/llvm.rs b/src/intrinsics/llvm.rs index e9b7daf14924..659e6c133ef5 100644 --- a/src/intrinsics/llvm.rs +++ b/src/intrinsics/llvm.rs @@ -12,6 +12,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( args: &[mir::Operand<'tcx>], ret: CPlace<'tcx>, target: Option, + span: Span, ) { if intrinsic.starts_with("llvm.aarch64") { return llvm_aarch64::codegen_aarch64_llvm_intrinsic_call( @@ -31,6 +32,7 @@ pub(crate) fn codegen_llvm_intrinsic_call<'tcx>( args, ret, target, + span, ); } diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 4c536048626e..8dd2b6ed014e 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -1,7 +1,10 @@ //! Emulate x86 LLVM intrinsics +use rustc_ast::ast::{InlineAsmOptions, InlineAsmTemplatePiece}; use rustc_middle::ty::GenericArgsRef; +use rustc_target::asm::*; +use crate::inline_asm::{codegen_inline_asm_inner, CInlineAsmOperand}; use crate::intrinsics::*; use crate::prelude::*; @@ -12,6 +15,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( args: &[mir::Operand<'tcx>], ret: CPlace<'tcx>, target: Option, + span: Span, ) { match intrinsic { "llvm.x86.sse2.pause" | "llvm.aarch64.isb" => { @@ -24,7 +28,35 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( let xcr_no = xcr_no.load_scalar(fx); - crate::inline_asm::codegen_xgetbv(fx, xcr_no, ret); + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String( + " + xgetbv + // out = rdx << 32 | rax + shl rdx, 32 + or rax, rdx + " + .to_string(), + )], + &[ + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)), + value: xcr_no, + }, + CInlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)), + late: true, + place: Some(ret), + }, + CInlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)), + late: true, + place: None, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); } "llvm.x86.sse3.ldu.dq" | "llvm.x86.avx.ldu.dq.256" => { @@ -688,64 +720,278 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( "llvm.x86.pclmulqdq" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_clmulepi64_si128&ig_expand=772 - intrinsic_args!(fx, args => (a, b, imm8); intrinsic); + intrinsic_args!(fx, args => (a, b, _imm8); intrinsic); - assert_eq!(a.layout(), b.layout()); - let layout = a.layout(); + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); - let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); - let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert_eq!(lane_ty, fx.tcx.types.i64); - assert_eq!(ret_lane_ty, fx.tcx.types.i64); - assert_eq!(lane_count, 2); - assert_eq!(ret_lane_count, 2); + let imm8 = if let Some(imm8) = crate::constant::mir_operand_get_const_val(fx, &args[2]) + { + imm8 + } else { + fx.tcx.sess.span_fatal( + span, + "Index argument for `_mm_clmulepi64_si128` is not a constant", + ); + }; - let imm8 = imm8.load_scalar(fx); + let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8)); - let control0 = fx.bcx.ins().band_imm(imm8, 0b0000_0001); - let a_lane0 = a.value_lane(fx, 0).load_scalar(fx); - let a_lane1 = a.value_lane(fx, 1).load_scalar(fx); - let temp1 = fx.bcx.ins().select(control0, a_lane1, a_lane0); + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String(format!("pclmulqdq xmm0, xmm1, {imm8}"))], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)), + value: b, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } - let control4 = fx.bcx.ins().band_imm(imm8, 0b0001_0000); - let b_lane0 = b.value_lane(fx, 0).load_scalar(fx); - let b_lane1 = b.value_lane(fx, 1).load_scalar(fx); - let temp2 = fx.bcx.ins().select(control4, b_lane1, b_lane0); + "llvm.x86.aesni.aeskeygenassist" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aeskeygenassist_si128&ig_expand=261 + intrinsic_args!(fx, args => (a, _imm8); intrinsic); - fn extract_bit(fx: &mut FunctionCx<'_, '_, '_>, val: Value, bit: i64) -> Value { - let tmp = fx.bcx.ins().ushr_imm(val, bit); - fx.bcx.ins().band_imm(tmp, 1) - } + let a = a.load_scalar(fx); - let mut res1 = fx.bcx.ins().iconst(types::I64, 0); - for i in 0..=63 { - let x = extract_bit(fx, temp1, 0); - let y = extract_bit(fx, temp2, i); - let mut temp = fx.bcx.ins().band(x, y); - for j in 1..=i { - let x = extract_bit(fx, temp1, j); - let y = extract_bit(fx, temp2, i - j); - let z = fx.bcx.ins().band(x, y); - temp = fx.bcx.ins().bxor(temp, z); - } - let temp = fx.bcx.ins().ishl_imm(temp, i); - res1 = fx.bcx.ins().bor(res1, temp); - } - ret.place_lane(fx, 0).to_ptr().store(fx, res1, MemFlags::trusted()); + let imm8 = if let Some(imm8) = crate::constant::mir_operand_get_const_val(fx, &args[1]) + { + imm8 + } else { + fx.tcx.sess.span_fatal( + span, + "Index argument for `_mm_aeskeygenassist_si128` is not a constant", + ); + }; - let mut res2 = fx.bcx.ins().iconst(types::I64, 0); - for i in 64..=127 { - let mut temp = fx.bcx.ins().iconst(types::I64, 0); - for j in i - 63..=63 { - let x = extract_bit(fx, temp1, j); - let y = extract_bit(fx, temp2, i - j); - let z = fx.bcx.ins().band(x, y); - temp = fx.bcx.ins().bxor(temp, z); - } - let temp = fx.bcx.ins().ishl_imm(temp, i); - res2 = fx.bcx.ins().bor(res2, temp); - } - ret.place_lane(fx, 1).to_ptr().store(fx, res2, MemFlags::trusted()); + let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8)); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String(format!("aeskeygenassist xmm0, xmm0, {imm8}"))], + &[CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + _late: true, + in_value: a, + out_place: Some(ret), + }], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.x86.aesni.aesimc" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesimc_si128&ig_expand=260 + intrinsic_args!(fx, args => (a); intrinsic); + + let a = a.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("aesimc xmm0, xmm0".to_string())], + &[CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + _late: true, + in_value: a, + out_place: Some(ret), + }], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.x86.aesni.aesenc" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenc_si128&ig_expand=252 + intrinsic_args!(fx, args => (a, round_key); intrinsic); + + let a = a.load_scalar(fx); + let round_key = round_key.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("aesenc xmm0, xmm1".to_string())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)), + value: round_key, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.x86.aesni.aesenclast" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesenclast_si128&ig_expand=257 + intrinsic_args!(fx, args => (a, round_key); intrinsic); + + let a = a.load_scalar(fx); + let round_key = round_key.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("aesenclast xmm0, xmm1".to_string())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)), + value: round_key, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.x86.aesni.aesdec" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdec_si128&ig_expand=242 + intrinsic_args!(fx, args => (a, round_key); intrinsic); + + let a = a.load_scalar(fx); + let round_key = round_key.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("aesdec xmm0, xmm1".to_string())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)), + value: round_key, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.x86.aesni.aesdeclast" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_aesdeclast_si128&ig_expand=247 + intrinsic_args!(fx, args => (a, round_key); intrinsic); + + let a = a.load_scalar(fx); + let round_key = round_key.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("aesdeclast xmm0, xmm1".to_string())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)), + value: round_key, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.x86.sha256rnds2" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha256rnds2_epu32&ig_expand=5977 + intrinsic_args!(fx, args => (a, b, k); intrinsic); + + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + let k = k.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("sha256rnds2 xmm1, xmm2".to_string())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm2)), + value: b, + }, + // Implicit argument to the sha256rnds2 instruction + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + value: k, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.x86.sha256msg1" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha256msg1_epu32&ig_expand=5975 + intrinsic_args!(fx, args => (a, b); intrinsic); + + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("sha256msg1 xmm1, xmm2".to_string())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm2)), + value: b, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.x86.sha256msg2" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_sha256msg2_epu32&ig_expand=5976 + intrinsic_args!(fx, args => (a, b); intrinsic); + + let a = a.load_scalar(fx); + let b = b.load_scalar(fx); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String("sha256msg2 xmm1, xmm2".to_string())], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm2)), + value: b, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); } "llvm.x86.avx.ptestz.256" => { diff --git a/src/intrinsics/simd.rs b/src/intrinsics/simd.rs index ea137c4ca1e8..0bd211fd614f 100644 --- a/src/intrinsics/simd.rs +++ b/src/intrinsics/simd.rs @@ -282,11 +282,11 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( fx.tcx.sess.span_fatal(span, "Index argument for `simd_insert` is not a constant"); }; - let idx = idx_const - .try_to_bits(Size::from_bytes(4 /* u32*/)) - .unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); + let idx: u32 = idx_const + .try_to_u32() + .unwrap_or_else(|_| panic!("kind not scalar: {:?}", idx_const)); let (lane_count, _lane_ty) = base.layout().ty.simd_size_and_type(fx.tcx); - if idx >= lane_count.into() { + if u64::from(idx) >= lane_count { fx.tcx.sess.span_fatal( fx.mir.span, format!("[simd_insert] idx {} >= lane_count {}", idx, lane_count), @@ -331,10 +331,10 @@ pub(super) fn codegen_simd_intrinsic_call<'tcx>( }; let idx = idx_const - .try_to_bits(Size::from_bytes(4 /* u32*/)) - .unwrap_or_else(|| panic!("kind not scalar: {:?}", idx_const)); + .try_to_u32() + .unwrap_or_else(|_| panic!("kind not scalar: {:?}", idx_const)); let (lane_count, _lane_ty) = v.layout().ty.simd_size_and_type(fx.tcx); - if idx >= lane_count.into() { + if u64::from(idx) >= lane_count { fx.tcx.sess.span_fatal( fx.mir.span, format!("[simd_extract] idx {} >= lane_count {}", idx, lane_count), From 97ca520c448fbfb405ba3560ce521b2e31c81cc2 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 16 Nov 2023 21:24:33 +0000 Subject: [PATCH 13/93] check-cfg needs -Zunstable-options --- build_system/tests.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/build_system/tests.rs b/build_system/tests.rs index ff71a567ed3a..f6e6ac6f1e8e 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -457,6 +457,7 @@ impl<'a> TestRunner<'a> { cmd.arg("--target"); cmd.arg(&self.target_compiler.triple); cmd.arg("-Cpanic=abort"); + cmd.arg("-Zunstable-options"); cmd.arg("--check-cfg=cfg(no_unstable_features)"); cmd.arg("--check-cfg=cfg(jit)"); cmd.args(args); From a06f3556aa1ce9b02f059dfecc15ac8ebee318f2 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Tue, 21 Nov 2023 10:15:59 +0100 Subject: [PATCH 14/93] the unadjusted ABI needs to pass aggregates by-value --- compiler/rustc_target/src/abi/call/mod.rs | 1 + compiler/rustc_ty_utils/src/abi.rs | 35 +++++++++++++++++++---- 2 files changed, 30 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_target/src/abi/call/mod.rs b/compiler/rustc_target/src/abi/call/mod.rs index f7c860cf56b9..e9730947389f 100644 --- a/compiler/rustc_target/src/abi/call/mod.rs +++ b/compiler/rustc_target/src/abi/call/mod.rs @@ -382,6 +382,7 @@ impl HomogeneousAggregate { } impl<'a, Ty> TyAndLayout<'a, Ty> { + /// Returns `true` if this is an aggregate type (including a ScalarPair!) fn is_aggregate(&self) -> bool { match self.abi { Abi::Uninhabited | Abi::Scalar(_) | Abi::Vector { .. } => false, diff --git a/compiler/rustc_ty_utils/src/abi.rs b/compiler/rustc_ty_utils/src/abi.rs index ec2fb4888ea6..9ad7a1f588ed 100644 --- a/compiler/rustc_ty_utils/src/abi.rs +++ b/compiler/rustc_ty_utils/src/abi.rs @@ -327,10 +327,15 @@ fn adjust_for_rust_scalar<'tcx>( } /// Ensure that the ABI makes basic sense. -fn fn_abi_sanity_check<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>) { +fn fn_abi_sanity_check<'tcx>( + cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, + fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + spec_abi: SpecAbi, +) { fn fn_arg_sanity_check<'tcx>( cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, fn_abi: &FnAbi<'tcx, Ty<'tcx>>, + spec_abi: SpecAbi, arg: &ArgAbi<'tcx, Ty<'tcx>>, ) { match &arg.mode { @@ -360,8 +365,8 @@ fn fn_abi_sanity_check<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, fn_abi: &FnAbi<' // (See issue: https://github.com/rust-lang/rust/issues/117271) assert!( matches!(&*cx.tcx.sess.target.arch, "wasm32" | "wasm64") - || fn_abi.conv == Conv::PtxKernel, - "`PassMode::Direct` for aggregates only allowed on wasm and `extern \"ptx-kernel\"` fns\nProblematic type: {:#?}", + || matches!(spec_abi, SpecAbi::PtxKernel | SpecAbi::Unadjusted), + r#"`PassMode::Direct` for aggregates only allowed for "unadjusted" and "ptx-kernel" functions and on wasm\nProblematic type: {:#?}"#, arg.layout, ); } @@ -391,9 +396,9 @@ fn fn_abi_sanity_check<'tcx>(cx: &LayoutCx<'tcx, TyCtxt<'tcx>>, fn_abi: &FnAbi<' } for arg in fn_abi.args.iter() { - fn_arg_sanity_check(cx, fn_abi, arg); + fn_arg_sanity_check(cx, fn_abi, spec_abi, arg); } - fn_arg_sanity_check(cx, fn_abi, &fn_abi.ret); + fn_arg_sanity_check(cx, fn_abi, spec_abi, &fn_abi.ret); } // FIXME(eddyb) perhaps group the signature/type-containing (or all of them?) @@ -522,7 +527,7 @@ fn fn_abi_new_uncached<'tcx>( }; fn_abi_adjust_for_abi(cx, &mut fn_abi, sig.abi, fn_def_id)?; debug!("fn_abi_new_uncached = {:?}", fn_abi); - fn_abi_sanity_check(cx, &fn_abi); + fn_abi_sanity_check(cx, &fn_abi, sig.abi); Ok(cx.tcx.arena.alloc(fn_abi)) } @@ -534,6 +539,24 @@ fn fn_abi_adjust_for_abi<'tcx>( fn_def_id: Option, ) -> Result<(), &'tcx FnAbiError<'tcx>> { if abi == SpecAbi::Unadjusted { + // The "unadjusted" ABI passes aggregates in "direct" mode. That's fragile but needed for + // some LLVM intrinsics. + fn unadjust<'tcx>(arg: &mut ArgAbi<'tcx, Ty<'tcx>>) { + // This still uses `PassMode::Pair` for ScalarPair types. That's unlikely to be intended, + // but who knows what breaks if we change this now. + if matches!(arg.layout.abi, Abi::Aggregate { .. }) { + assert!( + arg.layout.abi.is_sized(), + "'unadjusted' ABI does not support unsized arguments" + ); + } + arg.make_direct_deprecated(); + } + + unadjust(&mut fn_abi.ret); + for arg in fn_abi.args.iter_mut() { + unadjust(arg); + } return Ok(()); } From cd7218aa9f4cdbfec0bc90ca86a9caa9cd271938 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 11 Nov 2023 13:26:19 +0000 Subject: [PATCH 15/93] Update Cranelift to 0.102 --- Cargo.lock | 60 +++++++++++++++++++++++----------------------- Cargo.toml | 12 +++++----- src/pretty_clif.rs | 16 ++++++++----- 3 files changed, 46 insertions(+), 42 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index dcb6cc57584c..901d1dbea66b 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -21,9 +21,9 @@ checksum = "a4668cab20f66d8d020e1fbc0ebe47217433c1b6c8f2040faf858554e394ace6" [[package]] name = "arbitrary" -version = "1.3.0" +version = "1.3.2" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "e2d098ff73c1ca148721f37baad5ea6a465a13f9573aba8641fbbbae8164a54e" +checksum = "7d5a26814d8dcb93b0e5a0ff3c6d80a8843bafb21b39e8e18a6f05471870e110" [[package]] name = "bitflags" @@ -45,18 +45,18 @@ checksum = "baf1de4339761588bc0619e3cbc0120ee582ebb74b53b4efbf79117bd2da40fd" [[package]] name = "cranelift-bforest" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "f773437307980ac0f424bf9b9a5d0cd21a0f17248c6860c9a65bec8b5975f3fe" +checksum = "76eb38f2af690b5a4411d9a8782b6d77dabff3ca939e0518453ab9f9a4392d41" dependencies = [ "cranelift-entity", ] [[package]] name = "cranelift-codegen" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "443c2ac50e97fb7de1a0f862753fce3f27215558811a6fcee508eb0c3747fa79" +checksum = "39526c036b92912417e8931f52c1e235796688068d3efdbbd8b164f299d19156" dependencies = [ "bumpalo", "cranelift-bforest", @@ -75,39 +75,39 @@ dependencies = [ [[package]] name = "cranelift-codegen-meta" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "c5b174c411480c79ce0793c55042fa51bec27e486381d103a53cab3b480cb2db" +checksum = "fdb0deedc9fccf2db53a5a3c9c9d0163e44143b0d004dca9bf6ab6a0024cd79a" dependencies = [ "cranelift-codegen-shared", ] [[package]] name = "cranelift-codegen-shared" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "73fa0151a528066a369de6debeea4d4b23a32aba68b5add8c46d3dc8091ff434" +checksum = "cea2d1b274e45aa8e61e9103efa1ba82d4b5a19d12bd1fd10744c3b7380ba3ff" [[package]] name = "cranelift-control" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "b8adf1e6398493c9bea1190e37d28a0eb0eca5fddbc80e01e506cda34db92b1f" +checksum = "6ea5977559a71e63db79a263f0e81a89b996e8a38212c4281e37dd1dbaa8b65c" dependencies = [ "arbitrary", ] [[package]] name = "cranelift-entity" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4917e2ed3bb5fe87d0ed88395ca6d644018d119a034faedd1f3e1f2c33cd52b2" +checksum = "2f871ada808b58158d84dfc43a6a2e2d2756baaf4ed1c51fd969ca8330e6ca5c" [[package]] name = "cranelift-frontend" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "9aaadf1e7cf28886bbf046eaf7ef538997bc8a7e020e578ea4957b39da87d5a1" +checksum = "e8e6890f587ef59824b3debe577e68fdf9b307b3808c54b8d93a18fd0b70941b" dependencies = [ "cranelift-codegen", "log", @@ -117,15 +117,15 @@ dependencies = [ [[package]] name = "cranelift-isle" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "a67fda31b9d69eaa1c49a2081939454c45857596a9d45af6744680541c628b4c" +checksum = "a8d5fc6d5d3b52d1917002b17a8ecce448c2621b5bf394bb4e77e2f676893537" [[package]] name = "cranelift-jit" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "d6bf32710628e7ff298739f1ed80a0bfdafc0c6a3e284c4540b23f18e8889d4b" +checksum = "e8a2d7744f743f59d9646d7589ad22ea17ed0d71e04906eb77c31e99bc13bd8b" dependencies = [ "anyhow", "cranelift-codegen", @@ -143,9 +143,9 @@ dependencies = [ [[package]] name = "cranelift-module" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "4d693e93a0fbf56b4bc93cffe6b107c2e52f070e1111950505fc8c83ac440b9d" +checksum = "b96cb196334698e612c197d7d0ae59af5e07667306ec20d7be414717db400873" dependencies = [ "anyhow", "cranelift-codegen", @@ -154,9 +154,9 @@ dependencies = [ [[package]] name = "cranelift-native" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "76fb52ba71be98312f35e798d9e98e45ab2586f27584231bf7c644fa9501e8af" +checksum = "3e10c2e7faa65d4ae7de9a83b44f2c31aca7dc638e17d0a79572fdf8103d720b" dependencies = [ "cranelift-codegen", "libc", @@ -165,9 +165,9 @@ dependencies = [ [[package]] name = "cranelift-object" -version = "0.101.2" +version = "0.102.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "2551b2e185022b89e9efa5e04c0f17f679b86ef73d9f7feabc48b608ff23120d" +checksum = "83ce94e18756058af8a66e3c0ba1123ae15517c72162d8060d0cb0974642adf2" dependencies = [ "anyhow", "cranelift-codegen", @@ -295,9 +295,9 @@ checksum = "dd8b5dd2ae5ed71462c540258bedcb51965123ad7e7ccf4b9a8cafaa4a63576d" [[package]] name = "regalloc2" -version = "0.9.2" +version = "0.9.3" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "5b4dcbd3a2ae7fb94b5813fa0e957c6ab51bf5d0a8ee1b69e0c2d0f1e6eb8485" +checksum = "ad156d539c879b7a24a363a2016d77961786e71f48f2e2fc8302a92abd2429a6" dependencies = [ "hashbrown 0.13.2", "log", @@ -374,9 +374,9 @@ checksum = "49874b5167b65d7193b8aba1567f5c7d93d001cafc34600cee003eda787e483f" [[package]] name = "wasmtime-jit-icache-coherence" -version = "14.0.2" +version = "15.0.0" source = "registry+https://github.com/rust-lang/crates.io-index" -checksum = "0980a96b16abbdaf829858d2389697b1d6cfc6a903873fd74b7e47a6b1045584" +checksum = "b73ad1395eda136baec5ece7e079e0536a82ef73488e345456cc9b89858ad0ec" dependencies = [ "cfg-if", "libc", diff --git a/Cargo.toml b/Cargo.toml index 30db10f74571..20fcd2227321 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -8,12 +8,12 @@ crate-type = ["dylib"] [dependencies] # These have to be in sync with each other -cranelift-codegen = { version = "0.101.2", default-features = false, features = ["std", "unwind", "all-arch"] } -cranelift-frontend = { version = "0.101.2" } -cranelift-module = { version = "0.101.2" } -cranelift-native = { version = "0.101.2" } -cranelift-jit = { version = "0.101.2", optional = true } -cranelift-object = { version = "0.101.2" } +cranelift-codegen = { version = "0.102", default-features = false, features = ["std", "unwind", "all-arch"] } +cranelift-frontend = { version = "0.102" } +cranelift-module = { version = "0.102" } +cranelift-native = { version = "0.102" } +cranelift-jit = { version = "0.102", optional = true } +cranelift-object = { version = "0.102" } target-lexicon = "0.12.0" gimli = { version = "0.28", default-features = false, features = ["write"]} object = { version = "0.32", default-features = false, features = ["std", "read_core", "write", "archive", "coff", "elf", "macho", "pe"] } diff --git a/src/pretty_clif.rs b/src/pretty_clif.rs index da84e54a9163..02c0dcb8b1bd 100644 --- a/src/pretty_clif.rs +++ b/src/pretty_clif.rs @@ -58,11 +58,10 @@ use std::fmt; use std::io::Write; -use cranelift_codegen::{ - entity::SecondaryMap, - ir::entities::AnyEntity, - write::{FuncWriter, PlainWriter}, -}; +use cranelift_codegen::entity::SecondaryMap; +use cranelift_codegen::ir::entities::AnyEntity; +use cranelift_codegen::ir::Fact; +use cranelift_codegen::write::{FuncWriter, PlainWriter}; use rustc_middle::ty::layout::FnAbiOf; use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_session::config::{OutputFilenames, OutputType}; @@ -155,8 +154,13 @@ impl FuncWriter for &'_ CommentWriter { _func: &Function, entity: AnyEntity, value: &dyn fmt::Display, + maybe_fact: Option<&Fact>, ) -> fmt::Result { - write!(w, " {} = {}", entity, value)?; + if let Some(fact) = maybe_fact { + write!(w, " {} ! {} = {}", entity, fact, value)?; + } else { + write!(w, " {} = {}", entity, value)?; + } if let Some(comment) = self.entity_comments.get(&entity) { writeln!(w, " ; {}", comment.replace('\n', "\n; ")) From a5fcfad890b8b35aa5c4efeff0e5eae5ebc504c1 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 21 Nov 2023 17:00:43 +0100 Subject: [PATCH 16/93] Fix _mm_sad_epu8 implementation Fixes rust-lang/rustc_codegen_cranelift#1426 --- src/intrinsics/llvm_x86.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 8dd2b6ed014e..78a0a347cfc2 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -364,9 +364,11 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( for out_lane_idx in 0..lane_count / 8 { let mut lane_diff_acc = fx.bcx.ins().iconst(types::I64, 0); - for lane_idx in out_lane_idx * 8..out_lane_idx * 8 + 1 { + for lane_idx in out_lane_idx * 8..out_lane_idx * 8 + 8 { let a_lane = a.value_lane(fx, lane_idx).load_scalar(fx); + let a_lane = fx.bcx.ins().uextend(types::I16, a_lane); let b_lane = b.value_lane(fx, lane_idx).load_scalar(fx); + let b_lane = fx.bcx.ins().uextend(types::I16, b_lane); let lane_diff = fx.bcx.ins().isub(a_lane, b_lane); let abs_lane_diff = fx.bcx.ins().iabs(lane_diff); From 98ac114847bf2632cf66c8d7ac843a8e866cddf4 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sat, 4 Nov 2023 04:25:35 +0100 Subject: [PATCH 17/93] Add some tests --- tests/ui/or-patterns/exhaustiveness-pass.rs | 11 ++ .../exhaustiveness-unreachable-pattern.rs | 10 ++ .../exhaustiveness-unreachable-pattern.stderr | 72 +++++---- .../pointer-sized-int.allow.stderr | 2 +- .../pointer-sized-int.deny.stderr | 55 ++++--- .../integer-ranges/pointer-sized-int.rs | 33 +++-- .../slice-patterns-exhaustiveness.rs | 4 + .../slice-patterns-exhaustiveness.stderr | 42 ++++-- .../omitted-patterns.rs | 77 ++++++---- .../omitted-patterns.stderr | 140 +++++++----------- 10 files changed, 241 insertions(+), 205 deletions(-) diff --git a/tests/ui/or-patterns/exhaustiveness-pass.rs b/tests/ui/or-patterns/exhaustiveness-pass.rs index 428b9a19fe69..a52e08c507d8 100644 --- a/tests/ui/or-patterns/exhaustiveness-pass.rs +++ b/tests/ui/or-patterns/exhaustiveness-pass.rs @@ -35,6 +35,17 @@ fn main() { ((0, 0) | (1, 0),) => {} _ => {} } + match ((0, 0),) { + // Note how the second one would be redundant without the guard. + ((x, y) | (y, x),) if x == 0 => {} + _ => {} + } + match 0 { + // We don't warn the second one as redundant in general because of cases like the one above. + // We could technically do it if there are no bindings. + 0 | 0 if 0 == 0 => {} + _ => {} + } // This one caused ICE https://github.com/rust-lang/rust/issues/117378 match (0u8, 0) { diff --git a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs index 8429799cabf1..20a8d7549961 100644 --- a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs +++ b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.rs @@ -1,6 +1,7 @@ #![deny(unreachable_patterns)] // We wrap patterns in a tuple because top-level or-patterns were special-cased. +#[rustfmt::skip] fn main() { match (0u8,) { (1 | 2,) => {} @@ -73,6 +74,11 @@ fn main() { | 0] => {} //~ ERROR unreachable _ => {} } + match (true, 0) { + (true, 0 | 0) => {} //~ ERROR unreachable + (_, 0 | 0) => {} //~ ERROR unreachable + _ => {} + } match &[][..] { [0] => {} [0, _] => {} @@ -149,4 +155,8 @@ fn main() { | true, //~ ERROR unreachable false | true) => {} } + match (true, true) { + (x, y) + | (y, x) => {} //~ ERROR unreachable + } } diff --git a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr index 3f7d47dcb8ce..3616dda99812 100644 --- a/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr +++ b/tests/ui/or-patterns/exhaustiveness-unreachable-pattern.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:7:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:8:9 | LL | (1,) => {} | ^^^^ @@ -11,128 +11,140 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:12:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:13:9 | LL | (2,) => {} | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:18:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:19:9 | LL | (1 | 2,) => {} | ^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:23:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:24:9 | LL | (1, 3) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:24:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:25:9 | LL | (1, 4) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:25:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:26:9 | LL | (2, 4) => {} | ^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:26:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:27:9 | LL | (2 | 1, 4) => {} | ^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:28:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:29:9 | LL | (1, 4 | 5) => {} | ^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:36:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:37:9 | LL | (Some(1),) => {} | ^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:37:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:38:9 | LL | (None,) => {} | ^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:42:9 + --> $DIR/exhaustiveness-unreachable-pattern.rs:43:9 | LL | ((1..=4,),) => {} | ^^^^^^^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:47:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:48:14 | LL | (1 | 1,) => {} | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:51:19 + --> $DIR/exhaustiveness-unreachable-pattern.rs:52:19 | LL | (0 | 1) | 1 => {} | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:57:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:58:14 | LL | 0 | (0 | 0) => {} | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:57:18 + --> $DIR/exhaustiveness-unreachable-pattern.rs:58:18 | LL | 0 | (0 | 0) => {} | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:65:13 + --> $DIR/exhaustiveness-unreachable-pattern.rs:66:13 | LL | / Some( LL | | 0 | 0) => {} | |______________________^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:71:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:72:15 | LL | | 0 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:73:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:74:15 | LL | | 0] => {} | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:81:10 + --> $DIR/exhaustiveness-unreachable-pattern.rs:78:20 + | +LL | (true, 0 | 0) => {} + | ^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:79:17 + | +LL | (_, 0 | 0) => {} + | ^ + +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:87:10 | LL | [1 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:93:10 + --> $DIR/exhaustiveness-unreachable-pattern.rs:99:10 | LL | [true | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:100:36 + --> $DIR/exhaustiveness-unreachable-pattern.rs:106:36 | LL | (true | false, None | Some(true | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:105:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:111:14 | LL | (true | ^^^^ @@ -143,28 +155,34 @@ LL | (true | false, None | Some(t_or_f!())) => {} = note: this error originates in the macro `t_or_f` (in Nightly builds, run with -Z macro-backtrace for more info) error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:116:14 + --> $DIR/exhaustiveness-unreachable-pattern.rs:122:14 | LL | Some(0 | ^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:135:19 + --> $DIR/exhaustiveness-unreachable-pattern.rs:141:19 | LL | | false) => {} | ^^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:143:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:149:15 | LL | | true) => {} | ^^^^ error: unreachable pattern - --> $DIR/exhaustiveness-unreachable-pattern.rs:149:15 + --> $DIR/exhaustiveness-unreachable-pattern.rs:155:15 | LL | | true, | ^^^^ -error: aborting due to 26 previous errors +error: unreachable pattern + --> $DIR/exhaustiveness-unreachable-pattern.rs:160:15 + | +LL | | (y, x) => {} + | ^^^^^^ + +error: aborting due to 29 previous errors diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr index 7f26c93aa28a..02afa565d01c 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.allow.stderr @@ -1,5 +1,5 @@ error[E0004]: non-exhaustive patterns: type `usize` is non-empty - --> $DIR/pointer-sized-int.rs:54:11 + --> $DIR/pointer-sized-int.rs:59:11 | LL | match 7usize {} | ^^^^^^ diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr index d16ec5412db1..2949081039ab 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.deny.stderr @@ -9,7 +9,7 @@ LL | match 0usize { = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `usize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | -LL ~ 0 ..= usize::MAX => {}, +LL ~ 0..=usize::MAX => {}, LL + usize::MAX.. => todo!() | @@ -24,12 +24,12 @@ LL | match 0isize { = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL ~ isize::MIN ..= isize::MAX => {}, +LL ~ isize::MIN..=isize::MAX => {}, LL + ..isize::MIN | isize::MAX.. => todo!() | error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:25:8 + --> $DIR/pointer-sized-int.rs:24:8 | LL | m!(0usize, 0..=usize::MAX); | ^^^^^^ pattern `usize::MAX..` not covered @@ -43,7 +43,7 @@ LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() } | +++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:27:8 + --> $DIR/pointer-sized-int.rs:26:8 | LL | m!(0usize, 0..5 | 5..=usize::MAX); | ^^^^^^ pattern `usize::MAX..` not covered @@ -57,7 +57,7 @@ LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() } | +++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `usize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:29:8 + --> $DIR/pointer-sized-int.rs:28:8 | LL | m!(0usize, 0..usize::MAX | usize::MAX); | ^^^^^^ pattern `usize::MAX..` not covered @@ -71,7 +71,7 @@ LL | match $s { $($t)+ => {}, usize::MAX.. => todo!() } | +++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `(usize::MAX.., _)` not covered - --> $DIR/pointer-sized-int.rs:31:8 + --> $DIR/pointer-sized-int.rs:30:8 | LL | m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); | ^^^^^^^^^^^^^^ pattern `(usize::MAX.., _)` not covered @@ -85,7 +85,7 @@ LL | match $s { $($t)+ => {}, (usize::MAX.., _) => todo!() } | ++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:36:8 + --> $DIR/pointer-sized-int.rs:39:8 | LL | m!(0isize, isize::MIN..=isize::MAX); | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered @@ -99,7 +99,7 @@ LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } | ++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:38:8 + --> $DIR/pointer-sized-int.rs:41:8 | LL | m!(0isize, isize::MIN..5 | 5..=isize::MAX); | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered @@ -113,7 +113,21 @@ LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } | ++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:40:8 + --> $DIR/pointer-sized-int.rs:43:8 + | +LL | m!(0isize, isize::MIN..=-1 | 0 | 1..=isize::MAX); + | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered + | + = note: the matched value is of type `isize` + = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively + = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms + | +LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } + | ++++++++++++++++++++++++++++++++++++++++ + +error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered + --> $DIR/pointer-sized-int.rs:45:8 | LL | m!(0isize, isize::MIN..isize::MAX | isize::MAX); | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered @@ -127,10 +141,10 @@ LL | match $s { $($t)+ => {}, ..isize::MIN | isize::MAX.. => todo!() } | ++++++++++++++++++++++++++++++++++++++++ error[E0004]: non-exhaustive patterns: `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered - --> $DIR/pointer-sized-int.rs:42:8 + --> $DIR/pointer-sized-int.rs:48:9 | -LL | m!((0isize, true), (isize::MIN..5, true) - | ^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered +LL | (0isize, true), + | ^^^^^^^^^^^^^^ patterns `(..isize::MIN, _)` and `(isize::MAX.., _)` not covered | = note: the matched value is of type `(isize, bool)` = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively @@ -140,23 +154,8 @@ help: ensure that all possible cases are being handled by adding a match arm wit LL | match $s { $($t)+ => {}, (..isize::MIN, _) | (isize::MAX.., _) => todo!() } | ++++++++++++++++++++++++++++++++++++++++++++++++++ -error[E0004]: non-exhaustive patterns: `..isize::MIN` and `isize::MAX..` not covered - --> $DIR/pointer-sized-int.rs:47:11 - | -LL | match 0isize { - | ^^^^^^ patterns `..isize::MIN` and `isize::MAX..` not covered - | - = note: the matched value is of type `isize` - = note: `isize` does not have fixed minimum and maximum values, so half-open ranges are necessary to match exhaustively - = help: add `#![feature(precise_pointer_size_matching)]` to the crate attributes to enable precise `isize` matching -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms - | -LL ~ 1 ..= isize::MAX => {}, -LL + ..isize::MIN | isize::MAX.. => todo!() - | - error[E0004]: non-exhaustive patterns: type `usize` is non-empty - --> $DIR/pointer-sized-int.rs:54:11 + --> $DIR/pointer-sized-int.rs:59:11 | LL | match 7usize {} | ^^^^^^ diff --git a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs index 20a3cbe127f4..cf137dca5aa8 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs +++ b/tests/ui/pattern/usefulness/integer-ranges/pointer-sized-int.rs @@ -13,15 +13,14 @@ macro_rules! m { fn main() { match 0usize { //[deny]~^ ERROR non-exhaustive patterns - 0 ..= usize::MAX => {} + 0..=usize::MAX => {} } match 0isize { //[deny]~^ ERROR non-exhaustive patterns - isize::MIN ..= isize::MAX => {} + isize::MIN..=isize::MAX => {} } - m!(0usize, 0..); m!(0usize, 0..=usize::MAX); //[deny]~^ ERROR non-exhaustive patterns m!(0usize, 0..5 | 5..=usize::MAX); @@ -30,26 +29,32 @@ fn main() { //[deny]~^ ERROR non-exhaustive patterns m!((0usize, true), (0..5, true) | (5..=usize::MAX, true) | (0..=usize::MAX, false)); //[deny]~^ ERROR non-exhaustive patterns + + m!(0usize, 0..); + m!(0usize, 0..5 | 5..); + m!(0usize, ..5 | 5..); + m!((0usize, true), (0..5, true) | (5.., true) | (0.., false)); m!(0usize, 0..=usize::MAX | usize::MAX..); - m!(0isize, ..0 | 0..); m!(0isize, isize::MIN..=isize::MAX); //[deny]~^ ERROR non-exhaustive patterns m!(0isize, isize::MIN..5 | 5..=isize::MAX); //[deny]~^ ERROR non-exhaustive patterns + m!(0isize, isize::MIN..=-1 | 0 | 1..=isize::MAX); + //[deny]~^ ERROR non-exhaustive patterns m!(0isize, isize::MIN..isize::MAX | isize::MAX); //[deny]~^ ERROR non-exhaustive patterns - m!((0isize, true), (isize::MIN..5, true) - | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false)); - //[deny]~^^ ERROR non-exhaustive patterns - m!(0isize, ..=isize::MIN | isize::MIN..=isize::MAX | isize::MAX..); + m!( + (0isize, true), + (isize::MIN..5, true) | (5..=isize::MAX, true) | (isize::MIN..=isize::MAX, false) + ); + //[deny]~^^^ ERROR non-exhaustive patterns - match 0isize { - //[deny]~^ ERROR non-exhaustive patterns - isize::MIN ..= -1 => {} - 0 => {} - 1 ..= isize::MAX => {} - } + m!(0isize, ..0 | 0..); + m!(0isize, ..5 | 5..); + m!((0isize, true), (..5, true) + | (5.., true) | (..0 | 0.., false)); + m!(0isize, ..=isize::MIN | isize::MIN..=isize::MAX | isize::MAX..); match 7usize {} //~^ ERROR non-exhaustive patterns diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs index 46e0da5be9b4..c203a2a48c44 100644 --- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs +++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs @@ -43,6 +43,10 @@ fn main() { //~^ ERROR `&[_, ..]` not covered [] => {} } + match s { + //~^ ERROR `&_` not covered + [..] if false => {} + } match s { //~^ ERROR `&[_, _, ..]` not covered [] => {} diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr index fb6ecda3c4df..75b5314261c7 100644 --- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr +++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr @@ -89,9 +89,23 @@ LL ~ [] => {}, LL + &[_, ..] => todo!() | -error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered +error[E0004]: non-exhaustive patterns: `&_` not covered --> $DIR/slice-patterns-exhaustiveness.rs:46:11 | +LL | match s { + | ^ pattern `&_` not covered + | + = note: the matched value is of type `&[bool]` + = note: match arms with guards don't count towards exhaustivity +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown + | +LL ~ [..] if false => {}, +LL + &_ => todo!() + | + +error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered + --> $DIR/slice-patterns-exhaustiveness.rs:50:11 + | LL | match s { | ^ pattern `&[_, _, ..]` not covered | @@ -103,7 +117,7 @@ LL + &[_, _, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[false, ..]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:51:11 + --> $DIR/slice-patterns-exhaustiveness.rs:55:11 | LL | match s { | ^ pattern `&[false, ..]` not covered @@ -116,7 +130,7 @@ LL + &[false, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[false, _, ..]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:56:11 + --> $DIR/slice-patterns-exhaustiveness.rs:60:11 | LL | match s { | ^ pattern `&[false, _, ..]` not covered @@ -129,7 +143,7 @@ LL + &[false, _, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[_, .., false]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:62:11 + --> $DIR/slice-patterns-exhaustiveness.rs:66:11 | LL | match s { | ^ pattern `&[_, .., false]` not covered @@ -142,7 +156,7 @@ LL + &[_, .., false] => todo!() | error[E0004]: non-exhaustive patterns: `&[_, _, .., true]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:69:11 + --> $DIR/slice-patterns-exhaustiveness.rs:73:11 | LL | match s { | ^ pattern `&[_, _, .., true]` not covered @@ -155,7 +169,7 @@ LL + &[_, _, .., true] => todo!() | error[E0004]: non-exhaustive patterns: `&[true, _, .., _]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:76:11 + --> $DIR/slice-patterns-exhaustiveness.rs:80:11 | LL | match s { | ^ pattern `&[true, _, .., _]` not covered @@ -168,7 +182,7 @@ LL + &[true, _, .., _] => todo!() | error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:85:11 + --> $DIR/slice-patterns-exhaustiveness.rs:89:11 | LL | match s { | ^ patterns `&[]` and `&[_, _, ..]` not covered @@ -181,7 +195,7 @@ LL + &[] | &[_, _, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:89:11 + --> $DIR/slice-patterns-exhaustiveness.rs:93:11 | LL | match s { | ^ patterns `&[]` and `&[_, _, ..]` not covered @@ -194,7 +208,7 @@ LL + &[] | &[_, _, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:93:11 + --> $DIR/slice-patterns-exhaustiveness.rs:97:11 | LL | match s { | ^ patterns `&[]` and `&[_, _, ..]` not covered @@ -207,7 +221,7 @@ LL + &[] | &[_, _, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[]` and `&[_, _, ..]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:98:11 + --> $DIR/slice-patterns-exhaustiveness.rs:102:11 | LL | match s { | ^ patterns `&[]` and `&[_, _, ..]` not covered @@ -220,7 +234,7 @@ LL + &[] | &[_, _, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:103:11 + --> $DIR/slice-patterns-exhaustiveness.rs:107:11 | LL | match s { | ^ pattern `&[_, _, ..]` not covered @@ -233,7 +247,7 @@ LL + &[_, _, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[false]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:108:11 + --> $DIR/slice-patterns-exhaustiveness.rs:112:11 | LL | match s { | ^ pattern `&[false]` not covered @@ -246,7 +260,7 @@ LL + &[false] => todo!() | error[E0004]: non-exhaustive patterns: `&[false]` not covered - --> $DIR/slice-patterns-exhaustiveness.rs:121:11 + --> $DIR/slice-patterns-exhaustiveness.rs:125:11 | LL | match s1 { | ^^ pattern `&[false]` not covered @@ -258,6 +272,6 @@ LL ~ CONST1 => {}, LL + &[false] => todo!() | -error: aborting due to 20 previous errors +error: aborting due to 21 previous errors For more information about this error, try `rustc --explain E0004`. diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs index e0a6051a81fa..a6c1dc53f8b2 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.rs @@ -1,6 +1,7 @@ // Test that the `non_exhaustive_omitted_patterns` lint is triggered correctly. #![feature(non_exhaustive_omitted_patterns_lint, unstable_test_feature)] +#![deny(unreachable_patterns)] // aux-build:enums.rs extern crate enums; @@ -31,11 +32,21 @@ pub enum Bar { C, } +fn no_lint() { + let non_enum = NonExhaustiveEnum::Unit; + // Ok: without the attribute + match non_enum { + NonExhaustiveEnum::Unit => {} + NonExhaustiveEnum::Tuple(_) => {} + _ => {} + } +} + +#[deny(non_exhaustive_omitted_patterns)] fn main() { let enumeration = Bar::A; // Ok: this is a crate local non_exhaustive enum - #[deny(non_exhaustive_omitted_patterns)] match enumeration { Bar::A => {} Bar::B => {} @@ -44,14 +55,13 @@ fn main() { let non_enum = NonExhaustiveEnum::Unit; - // Ok: without the attribute + #[allow(non_exhaustive_omitted_patterns)] match non_enum { NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match non_enum { //~^ some variants are not matched explicitly NonExhaustiveEnum::Unit => {} @@ -59,7 +69,6 @@ fn main() { _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match non_enum { //~^ some variants are not matched explicitly NonExhaustiveEnum::Unit | NonExhaustiveEnum::Struct { .. } => {} @@ -68,7 +77,6 @@ fn main() { let x = 5; // We ignore the guard. - #[deny(non_exhaustive_omitted_patterns)] match non_enum { NonExhaustiveEnum::Unit if x > 10 => {} NonExhaustiveEnum::Tuple(_) => {} @@ -76,14 +84,12 @@ fn main() { _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match (non_enum, true) { (NonExhaustiveEnum::Unit, true) => {} (NonExhaustiveEnum::Tuple(_), false) => {} (NonExhaustiveEnum::Struct { .. }, false) => {} _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match (non_enum, true) { //~^ some variants are not matched explicitly (NonExhaustiveEnum::Unit, true) => {} @@ -91,14 +97,12 @@ fn main() { _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match (true, non_enum) { (true, NonExhaustiveEnum::Unit) => {} (false, NonExhaustiveEnum::Tuple(_)) => {} (false, NonExhaustiveEnum::Struct { .. }) => {} _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match (true, non_enum) { //~^ some variants are not matched explicitly (true, NonExhaustiveEnum::Unit) => {} @@ -106,7 +110,6 @@ fn main() { _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match Some(non_enum) { //~^ some variants are not matched explicitly Some(NonExhaustiveEnum::Unit) => {} @@ -116,7 +119,6 @@ fn main() { // Ok: all covered and not `unreachable-patterns` #[deny(unreachable_patterns)] - #[deny(non_exhaustive_omitted_patterns)] match non_enum { NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} @@ -124,7 +126,6 @@ fn main() { _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match NestedNonExhaustive::B { //~^ some variants are not matched explicitly NestedNonExhaustive::A(NonExhaustiveEnum::Unit) => {} @@ -133,54 +134,53 @@ fn main() { _ => {} } - #[warn(non_exhaustive_omitted_patterns)] match VariantNonExhaustive::Baz(1, 2) { VariantNonExhaustive::Baz(_, _) => {} VariantNonExhaustive::Bar { x, .. } => {} } //~^^ some fields are not explicitly listed - #[warn(non_exhaustive_omitted_patterns)] let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); //~^ some fields are not explicitly listed // Ok: this is local - #[warn(non_exhaustive_omitted_patterns)] let Foo { a, b, .. } = Foo::default(); - #[warn(non_exhaustive_omitted_patterns)] let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); //~^ some fields are not explicitly listed //~^^ some fields are not explicitly listed // Ok: this tests https://github.com/rust-lang/rust/issues/89382 - #[warn(non_exhaustive_omitted_patterns)] let MixedVisFields { a, b, .. } = MixedVisFields::default(); // Ok: this only has 1 variant - #[deny(non_exhaustive_omitted_patterns)] match NonExhaustiveSingleVariant::A(true) { NonExhaustiveSingleVariant::A(true) => {} _ => {} } // We can't catch the case below, so for consistency we don't catch this one either. - #[deny(non_exhaustive_omitted_patterns)] match NonExhaustiveSingleVariant::A(true) { _ => {} } // We can't catch this case, because this would require digging fully through all the values of // any type we encounter. We need to be able to only consider present constructors. - #[deny(non_exhaustive_omitted_patterns)] match &NonExhaustiveSingleVariant::A(true) { _ => {} } + match Some(NonExhaustiveSingleVariant::A(true)) { + Some(_) => {} + None => {} + } + match Some(&NonExhaustiveSingleVariant::A(true)) { + Some(_) => {} + None => {} + } + // Ok: we don't lint on `if let` expressions - #[deny(non_exhaustive_omitted_patterns)] if let NonExhaustiveEnum::Tuple(_) = non_enum {} - #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { //~^ some variants are not matched explicitly UnstableEnum::Stable => {} @@ -189,7 +189,6 @@ fn main() { } // Ok: the feature is on and all variants are matched - #[deny(non_exhaustive_omitted_patterns)] match UnstableEnum::Stable { UnstableEnum::Stable => {} UnstableEnum::Stable2 => {} @@ -198,52 +197,66 @@ fn main() { } // Ok: the feature is on and both variants are matched - #[deny(non_exhaustive_omitted_patterns)] match OnlyUnstableEnum::Unstable { OnlyUnstableEnum::Unstable => {} OnlyUnstableEnum::Unstable2 => {} _ => {} } - #[deny(non_exhaustive_omitted_patterns)] match OnlyUnstableEnum::Unstable { //~^ some variants are not matched explicitly OnlyUnstableEnum::Unstable => {} _ => {} } - #[warn(non_exhaustive_omitted_patterns)] let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); //~^ some fields are not explicitly listed // OK: both unstable fields are matched with feature on - #[warn(non_exhaustive_omitted_patterns)] let OnlyUnstableStruct { unstable, unstable2, .. } = OnlyUnstableStruct::new(); - #[warn(non_exhaustive_omitted_patterns)] let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); //~^ some fields are not explicitly listed // OK: both unstable and stable fields are matched with feature on - #[warn(non_exhaustive_omitted_patterns)] let UnstableStruct { stable, stable2, unstable, .. } = UnstableStruct::default(); // Ok: local bindings are allowed - #[deny(non_exhaustive_omitted_patterns)] let local = NonExhaustiveEnum::Unit; // Ok: missing patterns will be blocked by the pattern being refutable - #[deny(non_exhaustive_omitted_patterns)] let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; //~^ refutable pattern in local binding - #[deny(non_exhaustive_omitted_patterns)] + // Check that matching on a reference results in a correct diagnostic match &non_enum { //~^ some variants are not matched explicitly + //~| pattern `&NonExhaustiveEnum::Struct { .. }` not covered NonExhaustiveEnum::Unit => {} NonExhaustiveEnum::Tuple(_) => {} _ => {} } + + match (true, &non_enum) { + //~^ some variants are not matched explicitly + //~| patterns `(_, &NonExhaustiveEnum::Tuple(_))` and `(_, &NonExhaustiveEnum::Struct { .. })` not covered + (true, NonExhaustiveEnum::Unit) => {} + _ => {} + } + + match (&non_enum, true) { + //~^ some variants are not matched explicitly + //~| patterns `(&NonExhaustiveEnum::Tuple(_), _)` and `(&NonExhaustiveEnum::Struct { .. }, _)` not covered + (NonExhaustiveEnum::Unit, true) => {} + _ => {} + } + + match Some(&non_enum) { + //~^ some variants are not matched explicitly + //~| pattern `Some(&NonExhaustiveEnum::Struct { .. })` not covered + Some(NonExhaustiveEnum::Unit | NonExhaustiveEnum::Tuple(_)) => {} + _ => {} + } } #[deny(non_exhaustive_omitted_patterns)] diff --git a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr index 7db61f1241ea..1037033c4b74 100644 --- a/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr +++ b/tests/ui/rfcs/rfc-2008-non-exhaustive/omitted-patterns.stderr @@ -1,4 +1,4 @@ -warning: some fields are not explicitly listed +error: some fields are not explicitly listed --> $DIR/omitted-patterns.rs:139:9 | LL | VariantNonExhaustive::Bar { x, .. } => {} @@ -7,41 +7,31 @@ LL | VariantNonExhaustive::Bar { x, .. } => {} = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `VariantNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found note: the lint level is defined here - --> $DIR/omitted-patterns.rs:136:12 + --> $DIR/omitted-patterns.rs:45:8 | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | #[deny(non_exhaustive_omitted_patterns)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:144:9 +error: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:143:9 | LL | let FunctionalRecord { first_field, second_field, .. } = FunctionalRecord::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `third_field` not listed | = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `FunctionalRecord` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:143:12 - | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:152:29 +error: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:149:29 | LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `second_field` not listed | = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `NormalStruct` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:151:12 - | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:152:9 +error: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:149:9 | LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = NestedStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `foo` not listed @@ -49,117 +39,77 @@ LL | let NestedStruct { bar: NormalStruct { first_field, .. }, .. } = Nested = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `NestedStruct` and the `non_exhaustive_omitted_patterns` attribute was found -warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:216:9 +error: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:212:9 | LL | let OnlyUnstableStruct { unstable, .. } = OnlyUnstableStruct::new(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable2` not listed | = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `OnlyUnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:215:12 - | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -warning: some fields are not explicitly listed - --> $DIR/omitted-patterns.rs:224:9 +error: some fields are not explicitly listed + --> $DIR/omitted-patterns.rs:218:9 | LL | let UnstableStruct { stable, stable2, .. } = UnstableStruct::default(); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ field `unstable` not listed | = help: ensure that all fields are mentioned explicitly by adding the suggested fields = note: the pattern is of type `UnstableStruct` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:223:12 - | -LL | #[warn(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:55:11 + --> $DIR/omitted-patterns.rs:65:11 | LL | match non_enum { | ^^^^^^^^ pattern `NonExhaustiveEnum::Struct { .. }` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:54:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:63:11 + --> $DIR/omitted-patterns.rs:72:11 | LL | match non_enum { | ^^^^^^^^ pattern `NonExhaustiveEnum::Tuple(_)` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:62:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:87:11 + --> $DIR/omitted-patterns.rs:93:11 | LL | match (non_enum, true) { | ^^^^^^^^^^^^^^^^ pattern `(NonExhaustiveEnum::Struct { .. }, _)` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `(NonExhaustiveEnum, bool)` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:86:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:102:11 + --> $DIR/omitted-patterns.rs:106:11 | LL | match (true, non_enum) { | ^^^^^^^^^^^^^^^^ pattern `(_, NonExhaustiveEnum::Struct { .. })` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `(bool, NonExhaustiveEnum)` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:101:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:110:11 + --> $DIR/omitted-patterns.rs:113:11 | LL | match Some(non_enum) { | ^^^^^^^^^^^^^^ pattern `Some(NonExhaustiveEnum::Struct { .. })` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `Option` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:109:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:128:11 + --> $DIR/omitted-patterns.rs:129:11 | LL | match NestedNonExhaustive::B { | ^^^^^^^^^^^^^^^^^^^^^^ patterns `NestedNonExhaustive::C`, `NestedNonExhaustive::A(NonExhaustiveEnum::Tuple(_))` and `NestedNonExhaustive::A(NonExhaustiveEnum::Struct { .. })` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `NestedNonExhaustive` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:127:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly --> $DIR/omitted-patterns.rs:184:11 @@ -169,28 +119,18 @@ LL | match UnstableEnum::Stable { | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `UnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:183:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:209:11 + --> $DIR/omitted-patterns.rs:206:11 | LL | match OnlyUnstableEnum::Unstable { | ^^^^^^^^^^^^^^^^^^^^^^^^^^ pattern `OnlyUnstableEnum::Unstable2` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `OnlyUnstableEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:208:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0005]: refutable pattern in local binding - --> $DIR/omitted-patterns.rs:237:9 + --> $DIR/omitted-patterns.rs:228:9 | LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit; | ^^^^^^^^^^^^^^^ pattern `_` not covered @@ -204,19 +144,41 @@ LL | let local_refutable @ NonExhaustiveEnum::Unit = NonExhaustiveEnum::Unit | ++++++++++++++++ error: some variants are not matched explicitly - --> $DIR/omitted-patterns.rs:241:11 + --> $DIR/omitted-patterns.rs:232:11 | LL | match &non_enum { | ^^^^^^^^^ pattern `&NonExhaustiveEnum::Struct { .. }` not covered | = help: ensure that all variants are matched explicitly by adding the suggested match arms = note: the matched value is of type `&NonExhaustiveEnum` and the `non_exhaustive_omitted_patterns` attribute was found -note: the lint level is defined here - --> $DIR/omitted-patterns.rs:240:12 - | -LL | #[deny(non_exhaustive_omitted_patterns)] - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ -error: aborting due to 10 previous errors; 6 warnings emitted +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:240:11 + | +LL | match (true, &non_enum) { + | ^^^^^^^^^^^^^^^^^ patterns `(_, &NonExhaustiveEnum::Tuple(_))` and `(_, &NonExhaustiveEnum::Struct { .. })` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `(bool, &NonExhaustiveEnum)` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:247:11 + | +LL | match (&non_enum, true) { + | ^^^^^^^^^^^^^^^^^ patterns `(&NonExhaustiveEnum::Tuple(_), _)` and `(&NonExhaustiveEnum::Struct { .. }, _)` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `(&NonExhaustiveEnum, bool)` and the `non_exhaustive_omitted_patterns` attribute was found + +error: some variants are not matched explicitly + --> $DIR/omitted-patterns.rs:254:11 + | +LL | match Some(&non_enum) { + | ^^^^^^^^^^^^^^^ pattern `Some(&NonExhaustiveEnum::Struct { .. })` not covered + | + = help: ensure that all variants are matched explicitly by adding the suggested match arms + = note: the matched value is of type `Option<&NonExhaustiveEnum>` and the `non_exhaustive_omitted_patterns` attribute was found + +error: aborting due to 19 previous errors For more information about this error, try `rustc --explain E0005`. From 8ad33a887f15df642b12e6293f5037bb0a0b0ba0 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 5 Nov 2023 02:02:54 +0100 Subject: [PATCH 18/93] Tweak `lower_pattern` --- compiler/rustc_mir_build/src/thir/pattern/check_match.rs | 6 ++++-- 1 file changed, 4 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index 4cc3bbfcf43b..d1a2772c6554 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -279,8 +279,10 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> { } else { // Check the pattern for some things unrelated to exhaustiveness. let refutable = if cx.refutable { Refutable } else { Irrefutable }; - pat.walk_always(|pat| check_borrow_conflicts_in_at_patterns(self, pat)); - pat.walk_always(|pat| check_for_bindings_named_same_as_variants(self, pat, refutable)); + pat.walk_always(|pat| { + check_borrow_conflicts_in_at_patterns(self, pat); + check_for_bindings_named_same_as_variants(self, pat, refutable); + }); Ok(cx.pattern_arena.alloc(DeconstructedPat::from_pat(cx, pat))) } } From 25696cc0e9e09413763bdb289c5dae8a64a7e7c6 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 22 Nov 2023 03:25:10 +0100 Subject: [PATCH 19/93] Abstract over the list of `WitnessStack`s --- .../src/thir/pattern/usefulness.rs | 179 +++++++++++------- 1 file changed, 108 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 461c44a169c8..ec80e0fa5fc5 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -564,21 +564,21 @@ enum Usefulness<'tcx> { NoWitnesses { useful: bool }, /// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole /// pattern is unreachable. - WithWitnesses(Vec>), + WithWitnesses(WitnessMatrix<'tcx>), } impl<'tcx> Usefulness<'tcx> { fn new_useful(preference: ArmType) -> Self { match preference { // A single (empty) witness of reachability. - FakeExtraWildcard => WithWitnesses(vec![WitnessStack(vec![])]), + FakeExtraWildcard => WithWitnesses(WitnessMatrix::unit_witness()), RealArm => NoWitnesses { useful: true }, } } fn new_not_useful(preference: ArmType) -> Self { match preference { - FakeExtraWildcard => WithWitnesses(vec![]), + FakeExtraWildcard => WithWitnesses(WitnessMatrix::empty()), RealArm => NoWitnesses { useful: false }, } } @@ -607,53 +607,16 @@ impl<'tcx> Usefulness<'tcx> { /// that makes sense for the matrix pre-specialization. This new usefulness can then be merged /// with the results of specializing with the other constructors. fn apply_constructor( - self, + mut self, pcx: &PatCtxt<'_, '_, 'tcx>, matrix: &Matrix<'_, 'tcx>, // used to compute missing ctors ctor: &Constructor<'tcx>, ) -> Self { - match self { - NoWitnesses { .. } => self, - WithWitnesses(ref witnesses) if witnesses.is_empty() => self, - WithWitnesses(witnesses) => { - let new_witnesses = if let Constructor::Missing { .. } = ctor { - let mut missing = ConstructorSet::for_ty(pcx.cx, pcx.ty) - .compute_missing(pcx, matrix.heads().map(DeconstructedPat::ctor)); - if missing.iter().any(|c| c.is_non_exhaustive()) { - // We only report `_` here; listing other constructors would be redundant. - missing = vec![Constructor::NonExhaustive]; - } - - // We got the special `Missing` constructor, so each of the missing constructors - // gives a new pattern that is not caught by the match. - // We construct for each missing constructor a version of this constructor with - // wildcards for fields, i.e. that matches everything that can be built with it. - // For example, if `ctor` is a `Constructor::Variant` for `Option::Some`, we get - // the pattern `Some(_)`. - let new_patterns: Vec> = missing - .into_iter() - .map(|missing_ctor| WitnessPat::wild_from_ctor(pcx, missing_ctor.clone())) - .collect(); - - witnesses - .into_iter() - .flat_map(|witness| { - new_patterns.iter().map(move |pat| { - let mut stack = witness.clone(); - stack.0.push(pat.clone()); - stack - }) - }) - .collect() - } else { - witnesses - .into_iter() - .map(|witness| witness.apply_constructor(pcx, ctor)) - .collect() - }; - WithWitnesses(new_witnesses) - } + match &mut self { + NoWitnesses { .. } => {} + WithWitnesses(witnesses) => witnesses.apply_constructor(pcx, matrix, ctor), } + self } } @@ -663,9 +626,9 @@ enum ArmType { RealArm, } -/// A witness-tuple of non-exhaustiveness for error reporting, represented as a list of patterns (in -/// reverse order of construction) with wildcards inside to represent elements that can take any -/// inhabitant of the type as a value. +/// A partially-constructed witness of non-exhaustiveness for error reporting, represented as a list +/// of patterns (in reverse order of construction) with wildcards inside to represent elements that +/// can take any inhabitant of the type as a value. /// /// This mirrors `PatStack`: they function similarly, except `PatStack` contains user patterns we /// are inspecting, and `WitnessStack` contains witnesses we are constructing. @@ -723,30 +686,104 @@ impl<'tcx> WitnessStack<'tcx> { self.0.into_iter().next().unwrap() } - /// Constructs a partial witness for a pattern given a list of - /// patterns expanded by the specialization step. - /// - /// When a pattern P is discovered to be useful, this function is used bottom-up - /// to reconstruct a complete witness, e.g., a pattern P' that covers a subset - /// of values, V, where each value in that set is not covered by any previously - /// used patterns and is covered by the pattern P'. Examples: - /// - /// left_ty: tuple of 3 elements - /// pats: [10, 20, _] => (10, 20, _) - /// - /// left_ty: struct X { a: (bool, &'static str), b: usize} - /// pats: [(false, "foo"), 42] => X { a: (false, "foo"), b: 42 } - fn apply_constructor(mut self, pcx: &PatCtxt<'_, '_, 'tcx>, ctor: &Constructor<'tcx>) -> Self { - let pat = { - let len = self.0.len(); - let arity = ctor.arity(pcx); - let fields = self.0.drain((len - arity)..).rev().collect(); - WitnessPat::new(ctor.clone(), fields, pcx.ty) - }; - + /// Reverses specialization by the `Missing` constructor by pushing a whole new pattern. + fn push_pattern(&mut self, pat: WitnessPat<'tcx>) { self.0.push(pat); + } - self + /// Reverses specialization. Given a witness obtained after specialization, this constructs a + /// new witness valid for before specialization. Examples: + /// + /// ctor: tuple of 2 elements + /// pats: [false, "foo", _, true] + /// result: [(false, "foo"), _, true] + /// + /// ctor: Enum::Variant { a: (bool, &'static str), b: usize} + /// pats: [(false, "foo"), _, true] + /// result: [Enum::Variant { a: (false, "foo"), b: _ }, true] + fn apply_constructor(&mut self, pcx: &PatCtxt<'_, '_, 'tcx>, ctor: &Constructor<'tcx>) { + let len = self.0.len(); + let arity = ctor.arity(pcx); + let fields = self.0.drain((len - arity)..).rev().collect(); + let pat = WitnessPat::new(ctor.clone(), fields, pcx.ty); + self.0.push(pat); + } +} + +/// Represents a set of partially-constructed witnesses of non-exhaustiveness for error reporting. +/// This has similar invariants as `Matrix` does. +/// Throughout the exhaustiveness phase of the algorithm, `is_useful` maintains the invariant that +/// the union of the `Matrix` and the `WitnessMatrix` together matches the type exhaustively. By the +/// end of the algorithm, this has a single column, which contains the patterns that are missing for +/// the match to be exhaustive. +#[derive(Debug, Clone)] +pub struct WitnessMatrix<'tcx>(Vec>); + +impl<'tcx> WitnessMatrix<'tcx> { + /// New matrix with no rows. + fn empty() -> Self { + WitnessMatrix(vec![]) + } + /// New matrix with one row and no columns. + fn unit_witness() -> Self { + WitnessMatrix(vec![WitnessStack(vec![])]) + } + + /// Whether this has any rows. + fn is_empty(&self) -> bool { + self.0.is_empty() + } + /// Asserts that there is a single column and returns the patterns in it. + fn single_column(self) -> Vec> { + self.0.into_iter().map(|w| w.single_pattern()).collect() + } + + /// Reverses specialization by the `Missing` constructor by pushing a whole new pattern. + fn push_pattern(&mut self, pat: &WitnessPat<'tcx>) { + for witness in self.0.iter_mut() { + witness.push_pattern(pat.clone()) + } + } + + /// Reverses specialization by `ctor`. + fn apply_constructor( + &mut self, + pcx: &PatCtxt<'_, '_, 'tcx>, + matrix: &Matrix<'_, 'tcx>, // used to compute missing ctors + ctor: &Constructor<'tcx>, + ) { + if self.is_empty() { + return; + } + if matches!(ctor, Constructor::Missing { .. }) { + let missing_ctors = ConstructorSet::for_ty(pcx.cx, pcx.ty) + .compute_missing(pcx, matrix.heads().map(DeconstructedPat::ctor)); + // We got the special `Missing` constructor, so each of the missing constructors gives a + // new pattern that is not caught by the match. We list those patterns and push them + // onto our current witnesses. + if missing_ctors.iter().any(|c| c.is_non_exhaustive()) { + // We only report `_` here; listing other constructors would be redundant. + let pat = WitnessPat::wild_from_ctor(pcx, Constructor::NonExhaustive); + self.push_pattern(&pat); + } else { + let old_witnesses = std::mem::replace(self, Self::empty()); + for ctor in missing_ctors { + let pat = WitnessPat::wild_from_ctor(pcx, ctor.clone()); + let mut witnesses_with_missing_ctor = old_witnesses.clone(); + witnesses_with_missing_ctor.push_pattern(&pat); + self.extend(witnesses_with_missing_ctor) + } + } + } else { + for witness in self.0.iter_mut() { + witness.apply_constructor(pcx, ctor) + } + } + } + + /// Merges the rows of two witness matrices. Their column types must match. + fn extend(&mut self, other: Self) { + self.0.extend(other.0) } } @@ -1144,7 +1181,7 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( let v = PatStack::from_pattern(wild_pattern); let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, lint_root, false, true); let non_exhaustiveness_witnesses: Vec<_> = match usefulness { - WithWitnesses(pats) => pats.into_iter().map(|w| w.single_pattern()).collect(), + WithWitnesses(witness_matrix) => witness_matrix.single_column(), NoWitnesses { .. } => bug!(), }; From 6ee51426a9714a9f989a2a9c549d52b3dfc18c49 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 31 Oct 2023 00:40:41 +0100 Subject: [PATCH 20/93] Respect `split` invariants for `Opaque`s --- .../src/thir/pattern/deconstruct_pat.rs | 84 +++++++++++++------ 1 file changed, 59 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 479f6c0a3ca4..cf9a0af33ee1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -41,6 +41,13 @@ //! or-patterns; instead we just try the alternatives one-by-one. For details on splitting //! wildcards, see [`Constructor::split`]; for integer ranges, see //! [`IntRange::split`]; for slices, see [`Slice::split`]. +//! +//! ## Opaque patterns +//! +//! Some patterns, such as TODO, cannot be inspected, which we handle with `Constructor::Opaque`. +//! Since we know nothing of these patterns, we assume they never cover each other. In order to +//! respect the invariants of [`SplitConstructorSet`], we give each `Opaque` constructor a unique id +//! so we can recognize it. use std::cell::Cell; use std::cmp::{self, max, min, Ordering}; @@ -617,6 +624,18 @@ impl Slice { } } +/// A globally unique id to distinguish `Opaque` patterns. +#[derive(Clone, Debug, PartialEq, Eq)] +pub(super) struct OpaqueId(u32); + +impl OpaqueId { + fn new() -> Self { + use std::sync::atomic::{AtomicU32, Ordering}; + static OPAQUE_ID: AtomicU32 = AtomicU32::new(0); + OpaqueId(OPAQUE_ID.fetch_add(1, Ordering::SeqCst)) + } +} + /// A value can be decomposed into a constructor applied to some fields. This struct represents /// the constructor. See also `Fields`. /// @@ -642,10 +661,12 @@ pub(super) enum Constructor<'tcx> { Str(mir::Const<'tcx>), /// Array and slice patterns. Slice(Slice), - /// Constants that must not be matched structurally. They are treated as black - /// boxes for the purposes of exhaustiveness: we must not inspect them, and they - /// don't count towards making a match exhaustive. - Opaque, + /// Constants that must not be matched structurally. They are treated as black boxes for the + /// purposes of exhaustiveness: we must not inspect them, and they don't count towards making a + /// match exhaustive. + /// Carries an id that must be unique within a match. We need this to ensure the invariants of + /// [`SplitConstructorSet`]. + Opaque(OpaqueId), /// Or-pattern. Or, /// Wildcard pattern. @@ -663,6 +684,9 @@ pub(super) enum Constructor<'tcx> { } impl<'tcx> Constructor<'tcx> { + pub(super) fn is_wildcard(&self) -> bool { + matches!(self, Wildcard) + } pub(super) fn is_non_exhaustive(&self) -> bool { matches!(self, NonExhaustive) } @@ -728,7 +752,7 @@ impl<'tcx> Constructor<'tcx> { | F32Range(..) | F64Range(..) | Str(..) - | Opaque + | Opaque(..) | NonExhaustive | Hidden | Missing { .. } @@ -869,8 +893,10 @@ impl<'tcx> Constructor<'tcx> { } (Slice(self_slice), Slice(other_slice)) => self_slice.is_covered_by(*other_slice), - // We are trying to inspect an opaque constant. Thus we skip the row. - (Opaque, _) | (_, Opaque) => false, + // Opaque constructors don't interact with anything unless they come from the + // syntactically identical pattern. + (Opaque(self_id), Opaque(other_id)) => self_id == other_id, + (Opaque(..), _) | (_, Opaque(..)) => false, _ => span_bug!( pcx.span, @@ -1083,18 +1109,26 @@ impl ConstructorSet { { let mut present: SmallVec<[_; 1]> = SmallVec::new(); let mut missing = Vec::new(); - // Constructors in `ctors`, except wildcards. - let mut seen = ctors.filter(|c| !(matches!(c, Opaque | Wildcard))); + // Constructors in `ctors`, except wildcards and opaques. + let mut seen = Vec::new(); + for ctor in ctors.cloned() { + if let Constructor::Opaque(..) = ctor { + present.push(ctor); + } else if !ctor.is_wildcard() { + seen.push(ctor); + } + } + match self { ConstructorSet::Single => { - if seen.next().is_none() { + if seen.is_empty() { missing.push(Single); } else { present.push(Single); } } ConstructorSet::Variants { visible_variants, hidden_variants, non_exhaustive } => { - let seen_set: FxHashSet<_> = seen.map(|c| c.as_variant().unwrap()).collect(); + let seen_set: FxHashSet<_> = seen.iter().map(|c| c.as_variant().unwrap()).collect(); let mut skipped_a_hidden_variant = false; for variant in visible_variants { @@ -1125,7 +1159,7 @@ impl ConstructorSet { ConstructorSet::Bool => { let mut seen_false = false; let mut seen_true = false; - for b in seen.map(|ctor| ctor.as_bool().unwrap()) { + for b in seen.iter().map(|ctor| ctor.as_bool().unwrap()) { if b { seen_true = true; } else { @@ -1145,7 +1179,7 @@ impl ConstructorSet { } ConstructorSet::Integers { range_1, range_2 } => { let seen_ranges: Vec<_> = - seen.map(|ctor| ctor.as_int_range().unwrap().clone()).collect(); + seen.iter().map(|ctor| ctor.as_int_range().unwrap().clone()).collect(); for (seen, splitted_range) in range_1.split(seen_ranges.iter().cloned()) { match seen { Presence::Unseen => missing.push(IntRange(splitted_range)), @@ -1162,7 +1196,7 @@ impl ConstructorSet { } } &ConstructorSet::Slice(array_len) => { - let seen_slices = seen.map(|c| c.as_slice().unwrap()); + let seen_slices = seen.iter().map(|c| c.as_slice().unwrap()); let base_slice = Slice::new(array_len, VarLen(0, 0)); for (seen, splitted_slice) in base_slice.split(seen_slices) { let ctor = Slice(splitted_slice); @@ -1178,7 +1212,7 @@ impl ConstructorSet { // unreachable if length != 0. // We still gather the seen constructors in `present`, but the only slice that can // go in `missing` is `[]`. - let seen_slices = seen.map(|c| c.as_slice().unwrap()); + let seen_slices = seen.iter().map(|c| c.as_slice().unwrap()); let base_slice = Slice::new(None, VarLen(0, 0)); for (seen, splitted_slice) in base_slice.split(seen_slices) { let ctor = Slice(splitted_slice); @@ -1194,7 +1228,7 @@ impl ConstructorSet { ConstructorSet::Unlistable => { // Since we can't list constructors, we take the ones in the column. This might list // some constructors several times but there's not much we can do. - present.extend(seen.cloned()); + present.extend(seen); missing.push(NonExhaustive); } // If `exhaustive_patterns` is disabled and our scrutinee is an empty type, we cannot @@ -1339,7 +1373,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { | F32Range(..) | F64Range(..) | Str(..) - | Opaque + | Opaque(..) | NonExhaustive | Hidden | Missing { .. } @@ -1470,14 +1504,14 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { ty::Bool => { ctor = match value.try_eval_bool(cx.tcx, cx.param_env) { Some(b) => Bool(b), - None => Opaque, + None => Opaque(OpaqueId::new()), }; fields = Fields::empty(); } ty::Char | ty::Int(_) | ty::Uint(_) => { ctor = match value.try_eval_bits(cx.tcx, cx.param_env) { Some(bits) => IntRange(IntRange::from_bits(cx.tcx, pat.ty, bits)), - None => Opaque, + None => Opaque(OpaqueId::new()), }; fields = Fields::empty(); } @@ -1488,7 +1522,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let value = rustc_apfloat::ieee::Single::from_bits(bits); F32Range(value, value, RangeEnd::Included) } - None => Opaque, + None => Opaque(OpaqueId::new()), }; fields = Fields::empty(); } @@ -1499,7 +1533,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let value = rustc_apfloat::ieee::Double::from_bits(bits); F64Range(value, value, RangeEnd::Included) } - None => Opaque, + None => Opaque(OpaqueId::new()), }; fields = Fields::empty(); } @@ -1520,7 +1554,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { // into the corresponding `Pat`s by `const_to_pat`. Constants that remain are // opaque. _ => { - ctor = Opaque; + ctor = Opaque(OpaqueId::new()); fields = Fields::empty(); } } @@ -1581,7 +1615,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { fields = Fields::from_iter(cx, pats.into_iter().map(mkpat)); } PatKind::Error(_) => { - ctor = Opaque; + ctor = Opaque(OpaqueId::new()); fields = Fields::empty(); } } @@ -1768,7 +1802,7 @@ impl<'p, 'tcx> fmt::Debug for DeconstructedPat<'p, 'tcx> { F32Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"), F64Range(lo, hi, end) => write!(f, "{lo}{end}{hi}"), Str(value) => write!(f, "{value}"), - Opaque => write!(f, ""), + Opaque(..) => write!(f, ""), Or => { for pat in self.iter_fields() { write!(f, "{}{:?}", start_or_continue(" | "), pat)?; @@ -1898,7 +1932,7 @@ impl<'tcx> WitnessPat<'tcx> { "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, `Missing` should have been processed in `apply_constructors`" ), - F32Range(..) | F64Range(..) | Opaque | Or => { + F32Range(..) | F64Range(..) | Opaque(..) | Or => { bug!("can't convert to pattern: {:?}", self) } }; From d744aecabf71d3276c3cf3542ea92438c64213a1 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 15 Oct 2023 17:36:36 +0200 Subject: [PATCH 21/93] Keep rows with guards in the matrix --- .../src/thir/pattern/usefulness.rs | 84 +++++++++---------- tests/ui/pattern/usefulness/issue-3601.rs | 2 +- tests/ui/pattern/usefulness/issue-3601.stderr | 6 +- .../usefulness/match-non-exhaustive.stderr | 10 +-- .../slice-patterns-exhaustiveness.rs | 2 +- .../slice-patterns-exhaustiveness.stderr | 8 +- 6 files changed, 52 insertions(+), 60 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index ec80e0fa5fc5..65ae051c9b8c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -388,16 +388,17 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> { /// works well. #[derive(Clone)] pub(crate) struct PatStack<'p, 'tcx> { - pub(crate) pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, + pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, + is_under_guard: bool, } impl<'p, 'tcx> PatStack<'p, 'tcx> { - fn from_pattern(pat: &'p DeconstructedPat<'p, 'tcx>) -> Self { - Self::from_vec(smallvec![pat]) + fn from_pattern(pat: &'p DeconstructedPat<'p, 'tcx>, is_under_guard: bool) -> Self { + PatStack { pats: smallvec![pat], is_under_guard } } - fn from_vec(vec: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>) -> Self { - PatStack { pats: vec } + fn from_vec(vec: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, is_under_guard: bool) -> Self { + PatStack { pats: vec, is_under_guard } } fn is_empty(&self) -> bool { @@ -420,7 +421,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { // or-pattern. Panics if `self` is empty. fn expand_or_pat<'a>(&'a self) -> impl Iterator> + Captures<'a> { self.head().iter_fields().map(move |pat| { - let mut new_patstack = PatStack::from_pattern(pat); + let mut new_patstack = PatStack::from_pattern(pat, self.is_under_guard); new_patstack.pats.extend_from_slice(&self.pats[1..]); new_patstack }) @@ -430,7 +431,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { fn expand_and_extend<'a>(&'a self, matrix: &mut Matrix<'p, 'tcx>) { if !self.is_empty() && self.head().is_or_pat() { for pat in self.head().iter_fields() { - let mut new_patstack = PatStack::from_pattern(pat); + let mut new_patstack = PatStack::from_pattern(pat, self.is_under_guard); new_patstack.pats.extend_from_slice(&self.pats[1..]); if !new_patstack.is_empty() && new_patstack.head().is_or_pat() { new_patstack.expand_and_extend(matrix); @@ -456,7 +457,7 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { // `self.head()`. let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor); new_fields.extend_from_slice(&self.pats[1..]); - PatStack::from_vec(new_fields) + PatStack::from_vec(new_fields, self.is_under_guard) } } @@ -474,12 +475,12 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { /// A 2D matrix. #[derive(Clone)] pub(super) struct Matrix<'p, 'tcx> { - pub patterns: Vec>, + pub rows: Vec>, } impl<'p, 'tcx> Matrix<'p, 'tcx> { fn empty() -> Self { - Matrix { patterns: vec![] } + Matrix { rows: vec![] } } /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively @@ -488,15 +489,22 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { if !row.is_empty() && row.head().is_or_pat() { row.expand_and_extend(self); } else { - self.patterns.push(row); + self.rows.push(row); } } + fn rows<'a>( + &'a self, + ) -> impl Iterator> + Clone + DoubleEndedIterator + ExactSizeIterator + { + self.rows.iter() + } + /// Iterate over the first component of each row fn heads<'a>( &'a self, ) -> impl Iterator> + Clone + Captures<'a> { - self.patterns.iter().map(|r| r.head()) + self.rows().map(|r| r.head()) } /// This computes `S(constructor, self)`. See top of the file for explanations. @@ -506,7 +514,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { ctor: &Constructor<'tcx>, ) -> Matrix<'p, 'tcx> { let mut matrix = Matrix::empty(); - for row in &self.patterns { + for row in &self.rows { if ctor.is_covered_by(pcx, row.head().ctor()) { let new_row = row.pop_head_constructor(pcx, ctor); matrix.push(new_row); @@ -529,12 +537,12 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "\n")?; - let Matrix { patterns: m, .. } = self; + let Matrix { rows, .. } = self; let pretty_printed_matrix: Vec> = - m.iter().map(|row| row.iter().map(|pat| format!("{pat:?}")).collect()).collect(); + rows.iter().map(|row| row.iter().map(|pat| format!("{pat:?}")).collect()).collect(); - let column_count = m.iter().map(|row| row.len()).next().unwrap_or(0); - assert!(m.iter().all(|row| row.len() == column_count)); + let column_count = rows.iter().map(|row| row.len()).next().unwrap_or(0); + assert!(rows.iter().all(|row| row.len() == column_count)); let column_widths: Vec = (0..column_count) .map(|col| pretty_printed_matrix.iter().map(|row| row[col].len()).max().unwrap_or(0)) .collect(); @@ -816,19 +824,16 @@ fn is_useful<'p, 'tcx>( v: &PatStack<'p, 'tcx>, witness_preference: ArmType, lint_root: HirId, - is_under_guard: bool, is_top_level: bool, ) -> Usefulness<'tcx> { debug!(?matrix, ?v); - let Matrix { patterns: rows, .. } = matrix; - // The base case. We are pattern-matching on () and the return value is // based on whether our matrix has a row or not. // NOTE: This could potentially be optimized by checking rows.is_empty() // first and then, if v is non-empty, the return value is based on whether // the type of the tuple we're checking is inhabited or not. if v.is_empty() { - let ret = if rows.is_empty() { + let ret = if matrix.rows().all(|r| r.is_under_guard) { Usefulness::new_useful(witness_preference) } else { Usefulness::new_not_useful(witness_preference) @@ -837,7 +842,7 @@ fn is_useful<'p, 'tcx>( return ret; } - debug_assert!(rows.iter().all(|r| r.len() == v.len())); + debug_assert!(matrix.rows().all(|r| r.len() == v.len())); // If the first pattern is an or-pattern, expand it. let mut ret = Usefulness::new_not_useful(witness_preference); @@ -848,16 +853,13 @@ fn is_useful<'p, 'tcx>( for v in v.expand_or_pat() { debug!(?v); let usefulness = ensure_sufficient_stack(|| { - is_useful(cx, &matrix, &v, witness_preference, lint_root, is_under_guard, false) + is_useful(cx, &matrix, &v, witness_preference, lint_root, false) }); debug!(?usefulness); ret.extend(usefulness); - // If pattern has a guard don't add it to the matrix. - if !is_under_guard { - // We push the already-seen patterns into the matrix in order to detect redundant - // branches like `Some(_) | Some(0)`. - matrix.push(v); - } + // We push the already-seen patterns into the matrix in order to detect redundant + // branches like `Some(_) | Some(0)`. + matrix.push(v); } } else { let mut ty = v.head().ty(); @@ -865,7 +867,7 @@ fn is_useful<'p, 'tcx>( // Opaque types can't get destructured/split, but the patterns can // actually hint at hidden types, so we use the patterns' types instead. if let ty::Alias(ty::Opaque, ..) = ty.kind() { - if let Some(row) = rows.first() { + if let Some(row) = matrix.rows().next() { ty = row.head().ty(); } } @@ -885,15 +887,7 @@ fn is_useful<'p, 'tcx>( let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor); let v = v.pop_head_constructor(pcx, &ctor); let usefulness = ensure_sufficient_stack(|| { - is_useful( - cx, - &spec_matrix, - &v, - witness_preference, - lint_root, - is_under_guard, - false, - ) + is_useful(cx, &spec_matrix, &v, witness_preference, lint_root, false) }); let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor); ret.extend(usefulness); @@ -1163,11 +1157,9 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( .copied() .map(|arm| { debug!(?arm); - let v = PatStack::from_pattern(arm.pat); - is_useful(cx, &matrix, &v, RealArm, arm.hir_id, arm.has_guard, true); - if !arm.has_guard { - matrix.push(v); - } + let v = PatStack::from_pattern(arm.pat, arm.has_guard); + is_useful(cx, &matrix, &v, RealArm, arm.hir_id, true); + matrix.push(v); let reachability = if arm.pat.is_reachable() { Reachability::Reachable(arm.pat.unreachable_spans()) } else { @@ -1178,8 +1170,8 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( .collect(); let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP)); - let v = PatStack::from_pattern(wild_pattern); - let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, lint_root, false, true); + let v = PatStack::from_pattern(wild_pattern, false); + let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, lint_root, true); let non_exhaustiveness_witnesses: Vec<_> = match usefulness { WithWitnesses(witness_matrix) => witness_matrix.single_column(), NoWitnesses { .. } => bug!(), diff --git a/tests/ui/pattern/usefulness/issue-3601.rs b/tests/ui/pattern/usefulness/issue-3601.rs index a6d2b11f4eee..868e8c710272 100644 --- a/tests/ui/pattern/usefulness/issue-3601.rs +++ b/tests/ui/pattern/usefulness/issue-3601.rs @@ -31,7 +31,7 @@ fn main() { //~^ ERROR non-exhaustive patterns //~| NOTE the matched value is of type //~| NOTE match arms with guards don't count towards exhaustivity - //~| NOTE pattern `box _` not covered + //~| NOTE pattern `box ElementKind::HTMLImageElement(_)` not covered //~| NOTE `Box` defined here box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => true, }, diff --git a/tests/ui/pattern/usefulness/issue-3601.stderr b/tests/ui/pattern/usefulness/issue-3601.stderr index b8c987431012..581ae4762635 100644 --- a/tests/ui/pattern/usefulness/issue-3601.stderr +++ b/tests/ui/pattern/usefulness/issue-3601.stderr @@ -1,8 +1,8 @@ -error[E0004]: non-exhaustive patterns: `box _` not covered +error[E0004]: non-exhaustive patterns: `box ElementKind::HTMLImageElement(_)` not covered --> $DIR/issue-3601.rs:30:44 | LL | box NodeKind::Element(ed) => match ed.kind { - | ^^^^^^^ pattern `box _` not covered + | ^^^^^^^ pattern `box ElementKind::HTMLImageElement(_)` not covered | note: `Box` defined here --> $SRC_DIR/alloc/src/boxed.rs:LL:COL @@ -11,7 +11,7 @@ note: `Box` defined here help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown | LL ~ box ElementKind::HTMLImageElement(ref d) if d.image.is_some() => true, -LL ~ box _ => todo!(), +LL ~ box ElementKind::HTMLImageElement(_) => todo!(), | error: aborting due to previous error diff --git a/tests/ui/pattern/usefulness/match-non-exhaustive.stderr b/tests/ui/pattern/usefulness/match-non-exhaustive.stderr index 4fa3a729212b..1a0cc58f35df 100644 --- a/tests/ui/pattern/usefulness/match-non-exhaustive.stderr +++ b/tests/ui/pattern/usefulness/match-non-exhaustive.stderr @@ -10,18 +10,18 @@ help: ensure that all possible cases are being handled by adding a match arm wit LL | match 0 { 1 => (), i32::MIN..=0_i32 | 2_i32..=i32::MAX => todo!() } | ++++++++++++++++++++++++++++++++++++++++++++++++ -error[E0004]: non-exhaustive patterns: `_` not covered +error[E0004]: non-exhaustive patterns: `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered --> $DIR/match-non-exhaustive.rs:3:11 | LL | match 0 { 0 if false => () } - | ^ pattern `_` not covered + | ^ patterns `i32::MIN..=-1_i32` and `1_i32..=i32::MAX` not covered | = note: the matched value is of type `i32` = note: match arms with guards don't count towards exhaustivity -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | -LL | match 0 { 0 if false => (), _ => todo!() } - | ++++++++++++++ +LL | match 0 { 0 if false => (), i32::MIN..=-1_i32 | 1_i32..=i32::MAX => todo!() } + | +++++++++++++++++++++++++++++++++++++++++++++++++ error: aborting due to 2 previous errors diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs index c203a2a48c44..97ded70fc927 100644 --- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs +++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.rs @@ -44,7 +44,7 @@ fn main() { [] => {} } match s { - //~^ ERROR `&_` not covered + //~^ ERROR `&[]` and `&[_, ..]` not covered [..] if false => {} } match s { diff --git a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr index 75b5314261c7..a8786d02414c 100644 --- a/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr +++ b/tests/ui/pattern/usefulness/slice-patterns-exhaustiveness.stderr @@ -89,18 +89,18 @@ LL ~ [] => {}, LL + &[_, ..] => todo!() | -error[E0004]: non-exhaustive patterns: `&_` not covered +error[E0004]: non-exhaustive patterns: `&[]` and `&[_, ..]` not covered --> $DIR/slice-patterns-exhaustiveness.rs:46:11 | LL | match s { - | ^ pattern `&_` not covered + | ^ patterns `&[]` and `&[_, ..]` not covered | = note: the matched value is of type `&[bool]` = note: match arms with guards don't count towards exhaustivity -help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern or an explicit pattern as shown +help: ensure that all possible cases are being handled by adding a match arm with a wildcard pattern, a match arm with multiple or-patterns as shown, or multiple match arms | LL ~ [..] if false => {}, -LL + &_ => todo!() +LL + &[] | &[_, ..] => todo!() | error[E0004]: non-exhaustive patterns: `&[_, _, ..]` not covered From cc6936d577c9508d56485a025b9df797eefd3c21 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Mon, 23 Oct 2023 08:19:10 +0200 Subject: [PATCH 22/93] Fully rework the algorithm and its explanation --- .../src/thir/pattern/deconstruct_pat.rs | 272 ++-- .../src/thir/pattern/usefulness.rs | 1264 +++++++++-------- .../usefulness/integer-ranges/reachability.rs | 5 +- .../integer-ranges/reachability.stderr | 56 +- 4 files changed, 857 insertions(+), 740 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index cf9a0af33ee1..8c864c9f2ec7 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1,53 +1,94 @@ -//! [`super::usefulness`] explains most of what is happening in this file. As explained there, -//! values and patterns are made from constructors applied to fields. This file defines a -//! `Constructor` enum, a `Fields` struct, and various operations to manipulate them and convert -//! them from/to patterns. +//! As explained in [`super::usefulness`], values and patterns are made from constructors applied to +//! fields. This file defines a `Constructor` enum, a `Fields` struct, and various operations to +//! manipulate them and convert them from/to patterns. //! -//! There's one idea that is not detailed in [`super::usefulness`] because the details are not -//! needed there: _constructor splitting_. +//! There are two important bits of core logic in this file: constructor inclusion and constructor +//! splitting. Constructor inclusion, i.e. whether a constructor is included in/covered by another, +//! is straightforward and defined in [`Constructor::is_covered_by`]. //! -//! # Constructor splitting +//! Constructor splitting is mentioned in [`super::usefulness`] but not detailed. We describe it +//! precisely here. //! -//! The idea is as follows: given a constructor `c` and a matrix, we want to specialize in turn -//! with all the value constructors that are covered by `c`, and compute usefulness for each. -//! Instead of listing all those constructors (which is intractable), we group those value -//! constructors together as much as possible. Example: //! +//! # Constructor grouping and splitting +//! +//! As explained in the corresponding section in [`super::usefulness`], to make usefulness tractable +//! we need to group together constructors that have the same effect when they are used to +//! specialize the matrix. +//! +//! Example: //! ```compile_fail,E0004 //! match (0, false) { -//! (0 ..=100, true) => {} // `p_1` -//! (50..=150, false) => {} // `p_2` -//! (0 ..=200, _) => {} // `q` +//! (0 ..=100, true) => {} +//! (50..=150, false) => {} +//! (0 ..=200, _) => {} //! } //! ``` //! -//! The naive approach would try all numbers in the range `0..=200`. But we can be a lot more -//! clever: `0` and `1` for example will match the exact same rows, and return equivalent -//! witnesses. In fact all of `0..50` would. We can thus restrict our exploration to 4 -//! constructors: `0..50`, `50..=100`, `101..=150` and `151..=200`. That is enough and infinitely -//! more tractable. +//! In this example we can restrict specialization to 5 cases: `0..50`, `50..=100`, `101..=150`, +//! `151..=200` and `200..`. //! -//! We capture this idea in a function `split(p_1 ... p_n, c)` which returns a list of constructors -//! `c'` covered by `c`. Given such a `c'`, we require that all value ctors `c''` covered by `c'` -//! return an equivalent set of witnesses after specializing and computing usefulness. -//! In the example above, witnesses for specializing by `c''` covered by `0..50` will only differ -//! in their first element. +//! In [`super::usefulness`], we had said that `specialize` only takes value-only constructors. We +//! now relax this restriction: we allow `specialize` to take constructors like `0..50` as long as +//! we're careful to only do that with constructors that make sense. For example, `specialize(0..50, +//! (0..=100, true))` is sensible, but `specialize(50..=200, (0..=100, true))` is not. +//! +//! Constructor splitting looks at the constructors in the first column of the matrix and constructs +//! such a sensible set of constructors. Formally, we want to find a smallest disjoint set of +//! constructors: +//! - Whose union covers the whole type, and +//! - That have no non-trivial intersection with any of the constructors in the column (i.e. they're +//! each either disjoint with or covered by any given column constructor). +//! +//! We compute this in two steps: first [`ConstructorSet::for_ty`] determines the set of all +//! possible constructors for the type. Then [`ConstructorSet::split`] looks at the column of +//! constructors and splits the set into groups accordingly. The precise invariants of +//! [`ConstructorSet::split`] is described in [`SplitConstructorSet`]. +//! +//! Constructor splitting has two interesting special cases: integer range splitting (see +//! [`IntRange::split`]) and slice splitting (see [`Slice::split`]). +//! +//! +//! # The `Missing` constructor +//! +//! We detail a special case of constructor splitting that is a bit subtle. Take the following: +//! +//! ``` +//! enum Direction { North, South, East, West } +//! # let wind = (Direction::North, 0u8); +//! match wind { +//! (Direction::North, 50..) => {} +//! (_, _) => {} +//! } +//! ``` +//! +//! Here we expect constructor splitting to output two cases: `North`, and "everything else". This +//! "everything else" is represented by [`Constructor::Missing`]. Unlike other constructors, it's a +//! bit contextual: to know the exact list of constructors it represents we have to look at the +//! column. In practice however we don't need to, because by construction it only matches rows that +//! have wildcards. This is how this constructor is special: the only constructor that covers it is +//! `Wildcard`. +//! +//! The only place where we care about which constructors `Missing` represents is in diagnostics +//! (see `super::usefulness::WitnessMatrix::apply_constructor`). +//! +//! Extra special implementation detail: in fact, in the case where all the constructors are +//! missing, we replace `Missing` with `Wildcard` to signal this. It only makes a difference for +//! diagnostics: for `Missing` we list the missing constructors; for `Wildcard` we only output `_`. +//! +//! FIXME(Nadrieril): maybe `Missing { report_all: bool }` would be less confusing. +//! +//! We choose whether to specialize with `Missing`/`Wildcard` in +//! `super::usefulness::compute_exhaustiveness_and_reachability`. //! -//! We usually also ask that the `c'` together cover all of the original `c`. However we allow -//! skipping some constructors as long as it doesn't change whether the resulting list of witnesses -//! is empty of not. We use this in the wildcard `_` case. //! -//! Splitting is implemented in the [`Constructor::split`] function. We don't do splitting for -//! or-patterns; instead we just try the alternatives one-by-one. For details on splitting -//! wildcards, see [`Constructor::split`]; for integer ranges, see -//! [`IntRange::split`]; for slices, see [`Slice::split`]. //! //! ## Opaque patterns //! -//! Some patterns, such as TODO, cannot be inspected, which we handle with `Constructor::Opaque`. -//! Since we know nothing of these patterns, we assume they never cover each other. In order to -//! respect the invariants of [`SplitConstructorSet`], we give each `Opaque` constructor a unique id -//! so we can recognize it. +//! Some patterns, such as constants that are not allowed to be matched structurally, cannot be +//! inspected, which we handle with `Constructor::Opaque`. Since we know nothing of these patterns, +//! we assume they never cover each other. In order to respect the invariants of +//! [`SplitConstructorSet`], we give each `Opaque` constructor a unique id so we can recognize it. use std::cell::Cell; use std::cmp::{self, max, min, Ordering}; @@ -645,8 +686,8 @@ impl OpaqueId { /// `Fields`. #[derive(Clone, Debug, PartialEq)] pub(super) enum Constructor<'tcx> { - /// The constructor for patterns that have a single constructor, like tuples, struct patterns - /// and fixed-length arrays. + /// The constructor for patterns that have a single constructor, like tuples, struct patterns, + /// and references. Fixed-length arrays are treated separately with `Slice`. Single, /// Enum variants. Variant(VariantIdx), @@ -678,8 +719,8 @@ pub(super) enum Constructor<'tcx> { /// We use this for variants behind an unstable gate as well as /// `#[doc(hidden)]` ones. Hidden, - /// Fake extra constructor for constructors that are not seen in the matrix, as explained in the - /// code for [`Constructor::split`]. + /// Fake extra constructor for constructors that are not seen in the matrix, as explained at the + /// top of the file. Missing, } @@ -761,104 +802,12 @@ impl<'tcx> Constructor<'tcx> { } } - /// Some constructors (namely `Wildcard`, `IntRange` and `Slice`) actually stand for a set of - /// actual constructors (like variants, integers or fixed-sized slices). When specializing for - /// these constructors, we want to be specialising for the actual underlying constructors. - /// Naively, we would simply return the list of constructors they correspond to. We instead are - /// more clever: if there are constructors that we know will behave the same w.r.t. the current - /// matrix, we keep them grouped. For example, all slices of a sufficiently large length will - /// either be all useful or all non-useful with a given matrix. - /// - /// See the branches for details on how the splitting is done. - /// - /// This function may discard some irrelevant constructors if this preserves behavior. Eg. for - /// the `_` case, we ignore the constructors already present in the column, unless all of them - /// are. - pub(super) fn split<'a>( - &self, - pcx: &PatCtxt<'_, '_, 'tcx>, - ctors: impl Iterator> + Clone, - ) -> SmallVec<[Self; 1]> - where - 'tcx: 'a, - { - match self { - Wildcard => { - let split_set = ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, ctors); - if !split_set.missing.is_empty() { - // We are splitting a wildcard in order to compute its usefulness. Some constructors are - // not present in the column. The first thing we note is that specializing with any of - // the missing constructors would select exactly the rows with wildcards. Moreover, they - // would all return equivalent results. We can therefore group them all into a - // fictitious `Missing` constructor. - // - // As an important optimization, this function will skip all the present constructors. - // This is correct because specializing with any of the present constructors would - // select a strict superset of the wildcard rows, and thus would only find witnesses - // already found with the `Missing` constructor. - // This does mean that diagnostics are incomplete: in - // ``` - // match x { - // Some(true) => {} - // } - // ``` - // we report `None` as missing but not `Some(false)`. - // - // When all the constructors are missing we can equivalently return the `Wildcard` - // constructor on its own. The difference between `Wildcard` and `Missing` will then - // only be in diagnostics. - - // If some constructors are missing, we typically want to report those constructors, - // e.g.: - // ``` - // enum Direction { N, S, E, W } - // let Direction::N = ...; - // ``` - // we can report 3 witnesses: `S`, `E`, and `W`. - // - // However, if the user didn't actually specify a constructor - // in this arm, e.g., in - // ``` - // let x: (Direction, Direction, bool) = ...; - // let (_, _, false) = x; - // ``` - // we don't want to show all 16 possible witnesses `(, , - // true)` - we are satisfied with `(_, _, true)`. So if all constructors are missing we - // prefer to report just a wildcard `_`. - // - // The exception is: if we are at the top-level, for example in an empty match, we - // usually prefer to report the full list of constructors. - let all_missing = split_set.present.is_empty(); - let report_when_all_missing = - pcx.is_top_level && !IntRange::is_integral(pcx.ty); - let ctor = - if all_missing && !report_when_all_missing { Wildcard } else { Missing }; - smallvec![ctor] - } else { - split_set.present - } - } - // Fast-track if the range is trivial. - IntRange(this_range) if !this_range.is_singleton() => { - let column_ranges = ctors.filter_map(|ctor| ctor.as_int_range()).cloned(); - this_range.split(column_ranges).map(|(_, range)| IntRange(range)).collect() - } - Slice(this_slice @ Slice { kind: VarLen(..), .. }) => { - let column_slices = ctors.filter_map(|c| c.as_slice()); - this_slice.split(column_slices).map(|(_, slice)| Slice(slice)).collect() - } - // Any other constructor can be used unchanged. - _ => smallvec![self.clone()], - } - } - /// Returns whether `self` is covered by `other`, i.e. whether `self` is a subset of `other`. /// For the simple cases, this is simply checking for equality. For the "grouped" constructors, /// this checks for inclusion. // We inline because this has a single call site in `Matrix::specialize_constructor`. #[inline] pub(super) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool { - // This must be kept in sync with `is_covered_by_any`. match (self, other) { // Wildcards cover anything (_, Wildcard) => true, @@ -943,16 +892,20 @@ pub(super) enum ConstructorSet { /// `present` is morally the set of constructors present in the column, and `missing` is the set of /// constructors that exist in the type but are not present in the column. /// -/// More formally, they respect the following constraints: -/// - the union of `present` and `missing` covers the whole type -/// - `present` and `missing` are disjoint -/// - neither contains wildcards -/// - each constructor in `present` is covered by some non-wildcard constructor in the column -/// - together, the constructors in `present` cover all the non-wildcard constructor in the column -/// - non-wildcards in the column do no cover anything in `missing` -/// - constructors in `present` and `missing` are split for the column; in other words, they are -/// either fully included in or disjoint from each constructor in the column. This avoids -/// non-trivial intersections like between `0..10` and `5..15`. +/// More formally, if we discard wildcards from the column, this respects the following constraints: +/// 1. the union of `present` and `missing` covers the whole type +/// 2. each constructor in `present` is covered by something in the column +/// 3. no constructor in `missing` is covered by anything in the column +/// 4. each constructor in the column is equal to the union of one or more constructors in `present` +/// 5. `missing` does not contain empty constructors (see discussion about emptiness at the top of +/// the file); +/// 6. constructors in `present` and `missing` are split for the column; in other words, they are +/// either fully included in or fully disjoint from each constructor in the column. In other +/// words, there are no non-trivial intersections like between `0..10` and `5..15`. +/// +/// We must be particularly careful with weird constructors like `Opaque`: they're not formally part +/// of the `ConstructorSet` for the type, yet if we forgot to include them in `present` we would be +/// ignoring any row with `Opaque`s in the algorithm. Hence the importance of point 4. #[derive(Debug)] pub(super) struct SplitConstructorSet<'tcx> { pub(super) present: SmallVec<[Constructor<'tcx>; 1]>, @@ -960,6 +913,7 @@ pub(super) struct SplitConstructorSet<'tcx> { } impl ConstructorSet { + /// Creates a set that represents all the constructors of `ty`. #[instrument(level = "debug", skip(cx), ret)] pub(super) fn for_ty<'p, 'tcx>(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> Self { let make_range = |start, end| { @@ -1095,9 +1049,10 @@ impl ConstructorSet { } } - /// This is the core logical operation of exhaustiveness checking. This analyzes a column a - /// constructors to 1/ determine which constructors of the type (if any) are missing; 2/ split - /// constructors to handle non-trivial intersections e.g. on ranges or slices. + /// This analyzes a column of constructors to 1/ determine which constructors of the type (if + /// any) are missing; 2/ split constructors to handle non-trivial intersections e.g. on ranges + /// or slices. This can get subtle; see [`SplitConstructorSet`] for details of this operation + /// and its invariants. #[instrument(level = "debug", skip(self, pcx, ctors), ret)] pub(super) fn split<'a, 'tcx>( &self, @@ -1244,19 +1199,6 @@ impl ConstructorSet { SplitConstructorSet { present, missing } } - - /// Compute the set of constructors missing from this column. - /// This is only used for reporting to the user. - pub(super) fn compute_missing<'a, 'tcx>( - &self, - pcx: &PatCtxt<'_, '_, 'tcx>, - ctors: impl Iterator> + Clone, - ) -> Vec> - where - 'tcx: 'a, - { - self.split(pcx, ctors).missing - } } /// A value can be decomposed into a constructor applied to some fields. This struct represents @@ -1422,6 +1364,8 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { DeconstructedPat { ctor, fields, ty, span, reachable: Cell::new(false) } } + /// Note: the input patterns must have been lowered through + /// `super::check_match::MatchVisitor::lower_pattern`. pub(crate) fn from_pat(cx: &MatchCheckCtxt<'p, 'tcx>, pat: &Pat<'tcx>) -> Self { let mkpat = |pat| DeconstructedPat::from_pat(cx, pat); let ctor; @@ -1625,6 +1569,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { pub(super) fn is_or_pat(&self) -> bool { matches!(self.ctor, Or) } + /// Expand this (possibly-nested) or-pattern into its alternatives. pub(super) fn flatten_or_pat(&'p self) -> SmallVec<[&'p Self; 1]> { if self.is_or_pat() { self.iter_fields().flat_map(|p| p.flatten_or_pat()).collect() @@ -1697,7 +1642,17 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { self.reachable.set(true) } pub(super) fn is_reachable(&self) -> bool { - self.reachable.get() + if self.reachable.get() { + true + } else if self.is_or_pat() && self.iter_fields().any(|f| f.is_reachable()) { + // We always expand or patterns in the matrix, so we will never see the actual + // or-pattern (the one with constructor `Or`) in the column. As such, it will not be + // marked as reachable itself, only its children will. We recover this information here. + self.set_reachable(); + true + } else { + false + } } /// Report the spans of subpatterns that were not reachable, if any. @@ -1706,7 +1661,6 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { self.collect_unreachable_spans(&mut spans); spans } - fn collect_unreachable_spans(&self, spans: &mut Vec) { // We don't look at subpatterns if we already reported the whole pattern as unreachable. if !self.is_reachable() { diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 65ae051c9b8c..3819a6a95c21 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -1,3 +1,481 @@ +//! # Match exhaustiveness and reachability algorithm +//! +//! This file contains the logic for exhaustiveness and reachability checking for pattern-matching. +//! Specifically, given a list of patterns in a match, we can tell whether: +//! (a) a given pattern is reachable (reachability) +//! (b) the patterns cover every possible value for the type (exhaustiveness) +//! +//! The algorithm implemented here is inspired from the one described in [this +//! paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). We have however changed it in +//! various ways to accommodate the variety of patterns that Rust supports. We thus explain our +//! version here, without being as precise. +//! +//! Fun fact: computing exhaustiveness is NP-complete, because we can encode a SAT problem as an +//! exhaustiveness problem. See [here](https://niedzejkob.p4.team/rust-np) for the fun details. +//! +//! +//! # Summary +//! +//! The algorithm is given as input a list of patterns, one for each arm of a match, and computes +//! the following: +//! - a set of values that match none of the patterns (if any), +//! - for each subpattern (taking into account or-patterns), whether it would catch any value that +//! isn't caught by a pattern before it, i.e. whether it is reachable. +//! +//! To a first approximation, the algorithm works by exploring all possible values for the type +//! being matched on, and determining which arm(s) catch which value. To make this tractable we +//! cleverly group together values, as we'll see below. +//! +//! The entrypoint of this file is the [`compute_match_usefulness`] function, which computes +//! reachability for each subpattern and exhaustiveness for the whole match. +//! +//! In this page we explain the necessary concepts to understand how the algorithm works. +//! +//! +//! # Usefulness +//! +//! The central concept of this file is the notion of "usefulness". Given some patterns `p_1 .. +//! p_n`, a pattern `q` is said to be *useful* if there is a value that is matched by `q` and by +//! none of the `p_i`. We write `usefulness(p_1 .. p_n, q)` for a function that returns a list of +//! such values. The aim of this file is to compute it efficiently. +//! +//! This is enough to compute reachability: a pattern in a `match` expression is reachable iff it is +//! useful w.r.t. the patterns above it: +//! ```compile_fail,E0004 +//! # #![feature(exclusive_range_pattern)] +//! # fn foo() { +//! match Some(0u32) { +//! Some(0..100) => {}, +//! Some(90..190) => {}, // reachable: `Some(150)` is matched by this but not the branch above +//! Some(50..150) => {}, // unreachable: all the values this matches are already matched by +//! // the branches above +//! None => {}, // reachable: `None` is matched by this but not the branches above +//! } +//! # } +//! ``` +//! +//! This is also enough to compute exhaustiveness: a match is exhaustive iff the wildcard `_` +//! pattern is _not_ useful w.r.t. the patterns in the match. The values returned by `usefulness` +//! are used to tell the user which values are missing. +//! ```compile_fail,E0004 +//! # fn foo(x: Option) { +//! match x { +//! None => {}, +//! Some(0) => {}, +//! // not exhaustive: `_` is useful because it matches `Some(1)` +//! } +//! # } +//! ``` +//! +//! +//! # Constructors and fields +//! +//! In the value `Pair(Some(0), true)`, `Pair` is called the constructor of the value, and `Some(0)` +//! and `true` are its fields. Every matcheable value can be decomposed in this way. Examples of +//! constructors are: `Some`, `None`, `(,)` (the 2-tuple constructor), `Foo {..}` (the constructor +//! for a struct `Foo`), and `2` (the constructor for the number `2`). +//! +//! Each constructor takes a fixed number of fields; this is called its arity. `Pair` and `(,)` have +//! arity 2, `Some` has arity 1, `None` and `42` have arity 0. Each type has a known set of +//! constructors. Some types have many constructors (like `u64`) or even an infinitely many (like +//! `&str` and `&[T]`). +//! +//! Patterns are similar: `Pair(Some(_), _)` has constructor `Pair` and two fields. The difference +//! is that we get some extra pattern-only constructors, namely: the wildcard `_`, variable +//! bindings, integer ranges like `0..=10`, and variable-length slices like `[_, .., _]`. We treat +//! or-patterns separately, see the dedicated section below. +//! +//! Now to check if a value `v` matches a pattern `p`, we check if `v`'s constructor matches `p`'s +//! constructor, then recursively compare their fields if necessary. A few representative examples: +//! +//! - `matches!(v, _) := true` +//! - `matches!((v0, v1), (p0, p1)) := matches!(v0, p0) && matches!(v1, p1)` +//! - `matches!(Foo { bar: v0, baz: v1 }, Foo { bar: p0, baz: p1 }) := matches!(v0, p0) && matches!(v1, p1)` +//! - `matches!(Ok(v0), Ok(p0)) := matches!(v0, p0)` +//! - `matches!(Ok(v0), Err(p0)) := false` (incompatible variants) +//! - `matches!(v, 1..=100) := matches!(v, 1) || ... || matches!(v, 100)` +//! - `matches!([v0], [p0, .., p1]) := false` (incompatible lengths) +//! - `matches!([v0, v1, v2], [p0, .., p1]) := matches!(v0, p0) && matches!(v2, p1)` +//! +//! Constructors, fields and relevant operations are defined in the [`super::deconstruct_pat`] +//! module. The question of whether a constructor is matched by another one is answered by +//! [`Constructor::is_covered_by`]. +//! +//! Note 1: variable bindings (like the `x` in `Some(x)`) match anything, so we treat them as wildcards. +//! Note 2: this only applies to matcheable values. For example a value of type `Rc` can't be +//! deconstructed that way. +//! +//! +//! +//! # Specialization +//! +//! The examples in the previous section motivate the operation at the heart of the algorithm: +//! "specialization". It captures this idea of "removing one layer of constructor". +//! +//! `specialize(c, p)` takes a value-only constructor `c` and a pattern `p`, and returns a +//! pattern-tuple or nothing. It works as follows: +//! +//! - Specializing for the wrong constructor returns nothing +//! +//! - `specialize(None, Some(p0)) := ` +//! - `specialize([,,,], [p0]) := ` +//! +//! - Specializing for the correct constructor returns a tuple of the fields +//! +//! - `specialize(Variant1, Variant1(p0, p1, p2)) := (p0, p1, p2)` +//! - `specialize(Foo{ bar, baz, quz }, Foo { bar: p0, baz: p1, .. }) := (p0, p1, _)` +//! - `specialize([,,,], [p0, .., p1]) := (p0, _, _, p1)` +//! +//! We get the following property: for any values `v_1, .., v_n` of appropriate types, we have: +//! ```text +//! matches!(c(v_1, .., v_n), p) +//! <=> specialize(c, p) returns something +//! && matches!((v_1, .., v_n), specialize(c, p)) +//! ``` +//! +//! We also extend specialization to pattern-tuples by applying it to the first pattern: +//! `specialize(c, (p_0, .., p_n)) := specialize(c, p_0) ++ (p_1, .., p_m)` +//! where `++` is concatenation of tuples. +//! +//! +//! The previous property extends to pattern-tuples: +//! ```text +//! matches!((c(v_1, .., v_n), w_1, .., w_m), (p_0, p_1, .., p_m)) +//! <=> specialize(c, p_0) does not error +//! && matches!((v_1, .., v_n, w_1, .., w_m), specialize(c, (p_0, p_1, .., p_m))) +//! ``` +//! +//! Whether specialization returns something or not is given by [`Constructor::is_covered_by`]. +//! Specialization of a pattern is computed in [`DeconstructedPat::specialize`]. Specialization for +//! a pattern-tuple is computed in [`PatStack::pop_head_constructor`]. Finally, specialization for a +//! set of pattern-tuples is computed in [`Matrix::specialize_constructor`]. +//! +//! +//! +//! # Undoing specialization +//! +//! To construct witnesses we will need an inverse of specialization. If `c` is a constructor of +//! arity `n`, we define `unspecialize` as: +//! `unspecialize(c, (p_1, .., p_n, q_1, .., q_m)) := (c(p_1, .., p_n), q_1, .., q_m)`. +//! +//! This is done for a single witness-tuple in [`WitnessStack::apply_constructor`], and for a set of +//! witness-tuples in [`WitnessMatrix::apply_constructor`]. +//! +//! +//! +//! # Computing usefulness +//! +//! We now present a naive version of the algorithm for computing usefulness. From now on we operate +//! on pattern-tuples. +//! +//! Let `pt_1, .., pt_n` and `qt` be length-m tuples of patterns for the same type `(T_1, .., T_m)`. +//! We compute `usefulness(tp_1, .., tp_n, tq)` as follows: +//! +//! - Base case: `m == 0`. +//! The pattern-tuples are all empty, i.e. they're all `()`. Thus `tq` is useful iff there are +//! no rows above it, i.e. if `n == 0`. In that case we return `()` as a witness-tuple of +//! usefulness of `tq`. +//! +//! - Inductive case: `m > 0`. +//! In this naive version, we list all the possible constructors for values of type `T1` (we +//! will be more clever in the next section). +//! +//! - For each such constructor `c` for which `specialize(c, tq)` is not nothing: +//! - We recursively compute `usefulness(specialize(c, tp_1) ... specialize(c, tp_n), specialize(c, tq))`, +//! where we discard any `specialize(c, p_i)` that returns nothing. +//! - For each witness-tuple `w` found, we apply `unspecialize(c, w)` to it. +//! +//! - We return the all the witnesses found, if any. +//! +//! +//! Let's take the following example: +//! ```compile_fail,E0004 +//! # enum Enum { Variant1(()), Variant2(Option, u32)} +//! # use Enum::*; +//! # fn foo(x: Enum) { +//! match x { +//! Variant1(_) => {} // `p1` +//! Variant2(None, 0) => {} // `p2` +//! Variant2(Some(_), 0) => {} // `q` +//! } +//! # } +//! ``` +//! +//! To compute the usefulness of `q`, we would proceed as follows: +//! ```text +//! Start: +//! `tp1 = [Variant1(_)]` +//! `tp2 = [Variant2(None, 0)]` +//! `tq = [Variant2(Some(true), 0)]` +//! +//! Constructors are `Variant1` and `Variant2`. Only `Variant2` can specialize `tq`. +//! Specialize with `Variant2`: +//! `tp2 = [None, 0]` +//! `tq = [Some(true), 0]` +//! +//! Constructors are `None` and `Some`. Only `Some` can specialize `tq`. +//! Specialize with `Some`: +//! `tq = [true, 0]` +//! +//! Constructors are `false` and `true`. Only `true` can specialize `tq`. +//! Specialize with `true`: +//! `tq = [0]` +//! +//! Constructors are `0`, `1`, .. up to infinity. Only `0` can specialize `tq`. +//! Specialize with `0`: +//! `tq = []` +//! +//! m == 0 and n == 0, so `tq` is useful with witness `[]`. +//! `witness = []` +//! +//! Unspecialize with `0`: +//! `witness = [0]` +//! Unspecialize with `true`: +//! `witness = [true, 0]` +//! Unspecialize with `Some`: +//! `witness = [Some(true), 0]` +//! Unspecialize with `Variant2`: +//! `witness = [Variant2(Some(true), 0)]` +//! ``` +//! +//! Therefore `usefulness(tp_1, tp_2, tq)` returns the single witness-tuple `[Variant2(Some(true), 0)]`. +//! +//! +//! Computing the set of constructors for a type is done in [`ConstructorSet::for_ty`]. See the +//! following sections for more accurate versions of the algorithm and corresponding links. +//! +//! +//! +//! # Computing reachability and exhaustiveness in one go +//! +//! The algorithm we have described so far computes usefulness of each pattern in turn to check if +//! it is reachable, and ends by checking if `_` is useful to determine exhaustiveness of the whole +//! match. In practice, instead of doing "for each pattern { for each constructor { ... } }", we do +//! "for each constructor { for each pattern { ... } }". This allows us to compute everything in one +//! go. +//! +//! [`Matrix`] stores the set of pattern-tuples under consideration. We track reachability of each +//! row mutably in the matrix as we go along. We ignore witnesses of usefulness of the match rows. +//! We gather witnesses of the usefulness of `_` in [`WitnessMatrix`]. The algorithm that computes +//! all this is in [`compute_exhaustiveness_and_reachability`]. +//! +//! See the full example at the bottom of this documentation. +//! +//! +//! +//! # Making usefulness tractable: constructor splitting +//! +//! We're missing one last detail: which constructors do we list? Naively listing all value +//! constructors cannot work for types like `u64` or `&str`, so we need to be more clever. The final +//! clever idea for this algorithm is that we can group together constructors that behave the same. +//! +//! Examples: +//! ```compile_fail,E0004 +//! match (0, false) { +//! (0 ..=100, true) => {} +//! (50..=150, false) => {} +//! (0 ..=200, _) => {} +//! } +//! ``` +//! +//! In this example, trying any of `0`, `1`, .., `49` will give the same specialized matrix, and +//! thus the same reachability/exhaustiveness results. We can thus accelerate the algorithm by +//! trying them all at once. Here in fact, the only cases we need to consider are: `0..50`, +//! `50..=100`, `101..=150`,`151..=200` and `201..`. +//! +//! ``` +//! enum Direction { North, South, East, West } +//! # let wind = (Direction::North, 0u8); +//! match wind { +//! (Direction::North, 50..) => {} +//! (_, _) => {} +//! } +//! ``` +//! +//! In this example, trying any of `South`, `East`, `West` will give the same specialized matrix. By +//! the same reasoning, we only need to try two cases: `North`, and "everything else". +//! +//! We call _constructor splitting_ the operation that computes such a minimal set of cases to try. +//! This is done in [`ConstructorSet::split`] and explained in [`super::deconstruct_pat`]. +//! +//! +//! # Or-patterns +//! +//! What we have described so far works well if there are no or-patterns. To handle them, if the +//! first pattern of a row in the matrix is an or-pattern, we expand it by duplicating the rest of +//! the row as necessary. This is handled automatically in [`Matrix`]. +//! +//! This makes reachability tracking subtle, because we also want to compute whether an alternative +//! of an or-pattern is unreachable, e.g. in `Some(_) | Some(0)`. We track reachability of each +//! subpattern by interior mutability in [`DeconstructedPat`] with `set_reachable`/`is_reachable`. +//! +//! It's unfortunate that we have to use interior mutability, but believe me (Nadrieril), I have +//! tried [other](https://github.com/rust-lang/rust/pull/80104) +//! [solutions](https://github.com/rust-lang/rust/pull/80632) and nothing is remotely as simple. +//! +//! +//! +//! # Constants and opaques +//! +//! There are two kinds of constants in patterns: +//! +//! * literals (`1`, `true`, `"foo"`) +//! * named or inline consts (`FOO`, `const { 5 + 6 }`) +//! +//! The latter are converted into the corresponding patterns by a previous phase. For example +//! `const_to_pat(const { [1, 2, 3] })` becomes an `Array(vec![Const(1), Const(2), Const(3)])` +//! pattern. This gets problematic when comparing the constant via `==` would behave differently +//! from matching on the constant converted to a pattern. The situation around this is currently +//! unclear and the lang team is working on clarifying what we want to do there. In any case, there +//! are constants we will not turn into patterns. We capture these with `Constructor::Opaque`. These +//! `Opaque` patterns do not participate in exhaustiveness, specialization or overlap checking. +//! +//! +//! +//! # Full example +//! +//! We illustrate a full run of the algorithm on the following match. +//! +//! ```compile_fail,E0004 +//! # struct Pair(Option, bool); +//! # fn foo(x: Pair) -> u32 { +//! match x { +//! Pair(Some(0), _) => 1, +//! Pair(_, false) => 2, +//! Pair(Some(0), false) => 3, +//! } +//! # } +//! ``` +//! +//! We keep track of the original row for illustration purposes, this is not what the algorithm +//! actually does (it tracks reachability as a boolean on each row). +//! +//! ```text +//! ┐ Patterns: +//! │ 1. `[Pair(Some(0), _)]` +//! │ 2. `[Pair(_, false)]` +//! │ 3. `[Pair(Some(0), false)]` +//! │ +//! │ Specialize with `Pair`: +//! ├─┐ Patterns: +//! │ │ 1. `[Some(0), _]` +//! │ │ 2. `[_, false]` +//! │ │ 3. `[Some(0), false]` +//! │ │ +//! │ │ Specialize with `Some`: +//! │ ├─┐ Patterns: +//! │ │ │ 1. `[0, _]` +//! │ │ │ 2. `[_, false]` +//! │ │ │ 3. `[0, false]` +//! │ │ │ +//! │ │ │ Specialize with `0`: +//! │ │ ├─┐ Patterns: +//! │ │ │ │ 1. `[_]` +//! │ │ │ │ 3. `[false]` +//! │ │ │ │ +//! │ │ │ │ Specialize with `true`: +//! │ │ │ ├─┐ Patterns: +//! │ │ │ │ │ 1. `[]` +//! │ │ │ │ │ +//! │ │ │ │ │ We note arm 1 is reachable (by `Pair(Some(0), true)`). +//! │ │ │ ├─┘ +//! │ │ │ │ +//! │ │ │ │ Specialize with `false`: +//! │ │ │ ├─┐ Patterns: +//! │ │ │ │ │ 1. `[]` +//! │ │ │ │ │ 3. `[]` +//! │ │ │ │ │ +//! │ │ │ │ │ We note arm 1 is reachable (by `Pair(Some(0), false)`). +//! │ │ │ ├─┘ +//! │ │ ├─┘ +//! │ │ │ +//! │ │ │ Specialize with `1..`: +//! │ │ ├─┐ Patterns: +//! │ │ │ │ 2. `[false]` +//! │ │ │ │ +//! │ │ │ │ Specialize with `true`: +//! │ │ │ ├─┐ Patterns: +//! │ │ │ │ │ // no rows left +//! │ │ │ │ │ +//! │ │ │ │ │ We have found an unmatched value (`Pair(Some(1..), true)`)! This gives us a witness. +//! │ │ │ │ │ New witnesses: +//! │ │ │ │ │ `[]` +//! │ │ │ ├─┘ +//! │ │ │ │ Unspecialize new witnesses with `true`: +//! │ │ │ │ `[true]` +//! │ │ │ │ +//! │ │ │ │ Specialize with `false`: +//! │ │ │ ├─┐ Patterns: +//! │ │ │ │ │ 2. `[]` +//! │ │ │ │ │ +//! │ │ │ │ │ We note arm 2 is reachable (by `Pair(Some(1..), false)`). +//! │ │ │ ├─┘ +//! │ │ │ │ +//! │ │ │ │ Total witnesses for `1..`: +//! │ │ │ │ `[true]` +//! │ │ ├─┘ +//! │ │ │ Unspecialize new witnesses with `1..`: +//! │ │ │ `[1.., true]` +//! │ │ │ +//! │ │ │ Total witnesses for `Some`: +//! │ │ │ `[1.., true]` +//! │ ├─┘ +//! │ │ Unspecialize new witnesses with `Some`: +//! │ │ `[Some(1..), true]` +//! │ │ +//! │ │ Specialize with `None`: +//! │ ├─┐ Patterns: +//! │ │ │ 2. `[false]` +//! │ │ │ +//! │ │ │ Specialize with `true`: +//! │ │ ├─┐ Patterns: +//! │ │ │ │ // no rows left +//! │ │ │ │ +//! │ │ │ │ We have found an unmatched value (`Pair(None, true)`)! This gives us a witness. +//! │ │ │ │ New witnesses: +//! │ │ │ │ `[]` +//! │ │ ├─┘ +//! │ │ │ Unspecialize new witnesses with `true`: +//! │ │ │ `[true]` +//! │ │ │ +//! │ │ │ Specialize with `false`: +//! │ │ ├─┐ Patterns: +//! │ │ │ │ 2. `[]` +//! │ │ │ │ +//! │ │ │ │ We note arm 2 is reachable (by `Pair(None, false)`). +//! │ │ ├─┘ +//! │ │ │ +//! │ │ │ Total witnesses for `None`: +//! │ │ │ `[true]` +//! │ ├─┘ +//! │ │ Unspecialize new witnesses with `None`: +//! │ │ `[None, true]` +//! │ │ +//! │ │ Total witnesses for `Pair`: +//! │ │ `[Some(1..), true]` +//! │ │ `[None, true]` +//! ├─┘ +//! │ Unspecialize new witnesses with `Pair`: +//! │ `[Pair(Some(1..), true)]` +//! │ `[Pair(None, true)]` +//! │ +//! │ Final witnesses: +//! │ `[Pair(Some(1..), true)]` +//! │ `[Pair(None, true)]` +//! ┘ +//! ``` +//! +//! We conclude: +//! - Arm 3 is unreachable (it was never marked as reachable); +//! - The match is not exhaustive; +//! - Adding arms with `Pair(Some(1..), true)` and `Pair(None, true)` would make the match exhaustive. +//! +//! Note that when we're deep in the algorithm, we don't know what specialization steps got us here. +//! We can only figure out what our witnesses correspond to by unspecializing back up the stack. +//! +//! +//! # Tests +//! //! Note: tests specific to this file can be found in: //! //! - `ui/pattern/usefulness` @@ -8,305 +486,8 @@ //! - probably many others //! //! I (Nadrieril) prefer to put new tests in `ui/pattern/usefulness` unless there's a specific -//! reason not to, for example if they depend on a particular feature like `or_patterns`. -//! -//! ----- -//! -//! This file includes the logic for exhaustiveness and reachability checking for pattern-matching. -//! Specifically, given a list of patterns for a type, we can tell whether: -//! (a) each pattern is reachable (reachability) -//! (b) the patterns cover every possible value for the type (exhaustiveness) -//! -//! The algorithm implemented here is a modified version of the one described in [this -//! paper](http://moscova.inria.fr/~maranget/papers/warn/index.html). We have however generalized -//! it to accommodate the variety of patterns that Rust supports. We thus explain our version here, -//! without being as rigorous. -//! -//! -//! # Summary -//! -//! The core of the algorithm is the notion of "usefulness". A pattern `q` is said to be *useful* -//! relative to another pattern `p` of the same type if there is a value that is matched by `q` and -//! not matched by `p`. This generalizes to many `p`s: `q` is useful w.r.t. a list of patterns -//! `p_1 .. p_n` if there is a value that is matched by `q` and by none of the `p_i`. We write -//! `usefulness(p_1 .. p_n, q)` for a function that returns a list of such values. The aim of this -//! file is to compute it efficiently. -//! -//! This is enough to compute reachability: a pattern in a `match` expression is reachable iff it -//! is useful w.r.t. the patterns above it: -//! ```rust -//! # fn foo(x: Option) { -//! match x { -//! Some(_) => {}, -//! None => {}, // reachable: `None` is matched by this but not the branch above -//! Some(0) => {}, // unreachable: all the values this matches are already matched by -//! // `Some(_)` above -//! } -//! # } -//! ``` -//! -//! This is also enough to compute exhaustiveness: a match is exhaustive iff the wildcard `_` -//! pattern is _not_ useful w.r.t. the patterns in the match. The values returned by `usefulness` -//! are used to tell the user which values are missing. -//! ```compile_fail,E0004 -//! # fn foo(x: Option) { -//! match x { -//! Some(0) => {}, -//! None => {}, -//! // not exhaustive: `_` is useful because it matches `Some(1)` -//! } -//! # } -//! ``` -//! -//! The entrypoint of this file is the [`compute_match_usefulness`] function, which computes -//! reachability for each match branch and exhaustiveness for the whole match. -//! -//! -//! # Constructors and fields -//! -//! Note: we will often abbreviate "constructor" as "ctor". -//! -//! The idea that powers everything that is done in this file is the following: a (matchable) -//! value is made from a constructor applied to a number of subvalues. Examples of constructors are -//! `Some`, `None`, `(,)` (the 2-tuple constructor), `Foo {..}` (the constructor for a struct -//! `Foo`), and `2` (the constructor for the number `2`). This is natural when we think of -//! pattern-matching, and this is the basis for what follows. -//! -//! Some of the ctors listed above might feel weird: `None` and `2` don't take any arguments. -//! That's ok: those are ctors that take a list of 0 arguments; they are the simplest case of -//! ctors. We treat `2` as a ctor because `u64` and other number types behave exactly like a huge -//! `enum`, with one variant for each number. This allows us to see any matchable value as made up -//! from a tree of ctors, each having a set number of children. For example: `Foo { bar: None, -//! baz: Ok(0) }` is made from 4 different ctors, namely `Foo{..}`, `None`, `Ok` and `0`. -//! -//! This idea can be extended to patterns: they are also made from constructors applied to fields. -//! A pattern for a given type is allowed to use all the ctors for values of that type (which we -//! call "value constructors"), but there are also pattern-only ctors. The most important one is -//! the wildcard (`_`), and the others are integer ranges (`0..=10`), variable-length slices (`[x, -//! ..]`), and or-patterns (`Ok(0) | Err(_)`). Examples of valid patterns are `42`, `Some(_)`, `Foo -//! { bar: Some(0) | None, baz: _ }`. Note that a binder in a pattern (e.g. `Some(x)`) matches the -//! same values as a wildcard (e.g. `Some(_)`), so we treat both as wildcards. -//! -//! From this deconstruction we can compute whether a given value matches a given pattern; we -//! simply look at ctors one at a time. Given a pattern `p` and a value `v`, we want to compute -//! `matches!(v, p)`. It's mostly straightforward: we compare the head ctors and when they match -//! we compare their fields recursively. A few representative examples: -//! -//! - `matches!(v, _) := true` -//! - `matches!((v0, v1), (p0, p1)) := matches!(v0, p0) && matches!(v1, p1)` -//! - `matches!(Foo { bar: v0, baz: v1 }, Foo { bar: p0, baz: p1 }) := matches!(v0, p0) && matches!(v1, p1)` -//! - `matches!(Ok(v0), Ok(p0)) := matches!(v0, p0)` -//! - `matches!(Ok(v0), Err(p0)) := false` (incompatible variants) -//! - `matches!(v, 1..=100) := matches!(v, 1) || ... || matches!(v, 100)` -//! - `matches!([v0], [p0, .., p1]) := false` (incompatible lengths) -//! - `matches!([v0, v1, v2], [p0, .., p1]) := matches!(v0, p0) && matches!(v2, p1)` -//! - `matches!(v, p0 | p1) := matches!(v, p0) || matches!(v, p1)` -//! -//! Constructors, fields and relevant operations are defined in the [`super::deconstruct_pat`] module. -//! -//! Note: this constructors/fields distinction may not straightforwardly apply to every Rust type. -//! For example a value of type `Rc` can't be deconstructed that way, and `&str` has an -//! infinitude of constructors. There are also subtleties with visibility of fields and -//! uninhabitedness and various other things. The constructors idea can be extended to handle most -//! of these subtleties though; caveats are documented where relevant throughout the code. -//! -//! Whether constructors cover each other is computed by [`Constructor::is_covered_by`]. -//! -//! -//! # Specialization -//! -//! Recall that we wish to compute `usefulness(p_1 .. p_n, q)`: given a list of patterns `p_1 .. -//! p_n` and a pattern `q`, all of the same type, we want to find a list of values (called -//! "witnesses") that are matched by `q` and by none of the `p_i`. We obviously don't just -//! enumerate all possible values. From the discussion above we see that we can proceed -//! ctor-by-ctor: for each value ctor of the given type, we ask "is there a value that starts with -//! this constructor and matches `q` and none of the `p_i`?". As we saw above, there's a lot we can -//! say from knowing only the first constructor of our candidate value. -//! -//! Let's take the following example: -//! ```compile_fail,E0004 -//! # enum Enum { Variant1(()), Variant2(Option, u32)} -//! # fn foo(x: Enum) { -//! match x { -//! Enum::Variant1(_) => {} // `p1` -//! Enum::Variant2(None, 0) => {} // `p2` -//! Enum::Variant2(Some(_), 0) => {} // `q` -//! } -//! # } -//! ``` -//! -//! We can easily see that if our candidate value `v` starts with `Variant1` it will not match `q`. -//! If `v = Variant2(v0, v1)` however, whether or not it matches `p2` and `q` will depend on `v0` -//! and `v1`. In fact, such a `v` will be a witness of usefulness of `q` exactly when the tuple -//! `(v0, v1)` is a witness of usefulness of `q'` in the following reduced match: -//! -//! ```compile_fail,E0004 -//! # fn foo(x: (Option, u32)) { -//! match x { -//! (None, 0) => {} // `p2'` -//! (Some(_), 0) => {} // `q'` -//! } -//! # } -//! ``` -//! -//! This motivates a new step in computing usefulness, that we call _specialization_. -//! Specialization consist of filtering a list of patterns for those that match a constructor, and -//! then looking into the constructor's fields. This enables usefulness to be computed recursively. -//! -//! Instead of acting on a single pattern in each row, we will consider a list of patterns for each -//! row, and we call such a list a _pattern-stack_. The idea is that we will specialize the -//! leftmost pattern, which amounts to popping the constructor and pushing its fields, which feels -//! like a stack. We note a pattern-stack simply with `[p_1 ... p_n]`. -//! Here's a sequence of specializations of a list of pattern-stacks, to illustrate what's -//! happening: -//! ```ignore (illustrative) -//! [Enum::Variant1(_)] -//! [Enum::Variant2(None, 0)] -//! [Enum::Variant2(Some(_), 0)] -//! //==>> specialize with `Variant2` -//! [None, 0] -//! [Some(_), 0] -//! //==>> specialize with `Some` -//! [_, 0] -//! //==>> specialize with `true` (say the type was `bool`) -//! [0] -//! //==>> specialize with `0` -//! [] -//! ``` -//! -//! The function `specialize(c, p)` takes a value constructor `c` and a pattern `p`, and returns 0 -//! or more pattern-stacks. If `c` does not match the head constructor of `p`, it returns nothing; -//! otherwise if returns the fields of the constructor. This only returns more than one -//! pattern-stack if `p` has a pattern-only constructor. -//! -//! - Specializing for the wrong constructor returns nothing -//! -//! `specialize(None, Some(p0)) := []` -//! -//! - Specializing for the correct constructor returns a single row with the fields -//! -//! `specialize(Variant1, Variant1(p0, p1, p2)) := [[p0, p1, p2]]` -//! -//! `specialize(Foo{..}, Foo { bar: p0, baz: p1 }) := [[p0, p1]]` -//! -//! - For or-patterns, we specialize each branch and concatenate the results -//! -//! `specialize(c, p0 | p1) := specialize(c, p0) ++ specialize(c, p1)` -//! -//! - We treat the other pattern constructors as if they were a large or-pattern of all the -//! possibilities: -//! -//! `specialize(c, _) := specialize(c, Variant1(_) | Variant2(_, _) | ...)` -//! -//! `specialize(c, 1..=100) := specialize(c, 1 | ... | 100)` -//! -//! `specialize(c, [p0, .., p1]) := specialize(c, [p0, p1] | [p0, _, p1] | [p0, _, _, p1] | ...)` -//! -//! - If `c` is a pattern-only constructor, `specialize` is defined on a case-by-case basis. See -//! the discussion about constructor splitting in [`super::deconstruct_pat`]. -//! -//! -//! We then extend this function to work with pattern-stacks as input, by acting on the first -//! column and keeping the other columns untouched. -//! -//! Specialization for the whole matrix is done in [`Matrix::specialize_constructor`]. Note that -//! or-patterns in the first column are expanded before being stored in the matrix. Specialization -//! for a single patstack is done from a combination of [`Constructor::is_covered_by`] and -//! [`PatStack::pop_head_constructor`]. The internals of how it's done mostly live in the -//! [`super::deconstruct_pat::Fields`] struct. -//! -//! -//! # Computing usefulness -//! -//! We now have all we need to compute usefulness. The inputs to usefulness are a list of -//! pattern-stacks `p_1 ... p_n` (one per row), and a new pattern_stack `q`. The paper and this -//! file calls the list of patstacks a _matrix_. They must all have the same number of columns and -//! the patterns in a given column must all have the same type. `usefulness` returns a (possibly -//! empty) list of witnesses of usefulness. These witnesses will also be pattern-stacks. -//! -//! - base case: `n_columns == 0`. -//! Since a pattern-stack functions like a tuple of patterns, an empty one functions like the -//! unit type. Thus `q` is useful iff there are no rows above it, i.e. if `n == 0`. -//! -//! - inductive case: `n_columns > 0`. -//! We need a way to list the constructors we want to try. We will be more clever in the next -//! section but for now assume we list all value constructors for the type of the first column. -//! -//! - for each such ctor `c`: -//! -//! - for each `q'` returned by `specialize(c, q)`: -//! -//! - we compute `usefulness(specialize(c, p_1) ... specialize(c, p_n), q')` -//! -//! - for each witness found, we revert specialization by pushing the constructor `c` on top. -//! -//! - We return the concatenation of all the witnesses found, if any. -//! -//! Example: -//! ```ignore (illustrative) -//! [Some(true)] // p_1 -//! [None] // p_2 -//! [Some(_)] // q -//! //==>> try `None`: `specialize(None, q)` returns nothing -//! //==>> try `Some`: `specialize(Some, q)` returns a single row -//! [true] // p_1' -//! [_] // q' -//! //==>> try `true`: `specialize(true, q')` returns a single row -//! [] // p_1'' -//! [] // q'' -//! //==>> base case; `n != 0` so `q''` is not useful. -//! //==>> go back up a step -//! [true] // p_1' -//! [_] // q' -//! //==>> try `false`: `specialize(false, q')` returns a single row -//! [] // q'' -//! //==>> base case; `n == 0` so `q''` is useful. We return the single witness `[]` -//! witnesses: -//! [] -//! //==>> undo the specialization with `false` -//! witnesses: -//! [false] -//! //==>> undo the specialization with `Some` -//! witnesses: -//! [Some(false)] -//! //==>> we have tried all the constructors. The output is the single witness `[Some(false)]`. -//! ``` -//! -//! This computation is done in [`is_useful`]. In practice we don't care about the list of -//! witnesses when computing reachability; we only need to know whether any exist. We do keep the -//! witnesses when computing exhaustiveness to report them to the user. -//! -//! -//! # Making usefulness tractable: constructor splitting -//! -//! We're missing one last detail: which constructors do we list? Naively listing all value -//! constructors cannot work for types like `u64` or `&str`, so we need to be more clever. The -//! first obvious insight is that we only want to list constructors that are covered by the head -//! constructor of `q`. If it's a value constructor, we only try that one. If it's a pattern-only -//! constructor, we use the final clever idea for this algorithm: _constructor splitting_, where we -//! group together constructors that behave the same. -//! -//! The details are not necessary to understand this file, so we explain them in -//! [`super::deconstruct_pat`]. Splitting is done by the [`Constructor::split`] function. -//! -//! # Constants in patterns -//! -//! There are two kinds of constants in patterns: -//! -//! * literals (`1`, `true`, `"foo"`) -//! * named or inline consts (`FOO`, `const { 5 + 6 }`) -//! -//! The latter are converted into other patterns with literals at the leaves. For example -//! `const_to_pat(const { [1, 2, 3] })` becomes an `Array(vec![Const(1), Const(2), Const(3)])` -//! pattern. This gets problematic when comparing the constant via `==` would behave differently -//! from matching on the constant converted to a pattern. Situations like that can occur, when -//! the user implements `PartialEq` manually, and thus could make `==` behave arbitrarily different. -//! In order to honor the `==` implementation, constants of types that implement `PartialEq` manually -//! stay as a full constant and become an `Opaque` pattern. These `Opaque` patterns do not participate -//! in exhaustiveness, specialization or overlap checking. +//! reason not to, for example if they crucially depend on a particular feature like `or_patterns`. -use self::ArmType::*; -use self::Usefulness::*; use super::deconstruct_pat::{ Constructor, ConstructorSet, DeconstructedPat, IntRange, MaybeInfiniteInt, SplitConstructorSet, WitnessPat, @@ -384,21 +565,39 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> { } } -/// A row of a matrix. Rows of len 1 are very common, which is why `SmallVec[_; 2]` -/// works well. +/// A row of the matrix. Represents a pattern-tuple under investigation. #[derive(Clone)] -pub(crate) struct PatStack<'p, 'tcx> { +struct PatStack<'p, 'tcx> { + // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well. pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, + /// Whether the original arm had a guard. is_under_guard: bool, + /// When we specialize, we remember which row of the original matrix produced a given row of the + /// specialized matrix. When we unspecialize, we use this to propagate reachability back up the + /// callstack. + /// At the start of the algorithm, this is the id of the arm this comes from (but we don't use + /// this fact anywhere). + parent_row: usize, + /// False when the matrix is just built. This is set to `true` by + /// [`compute_exhaustiveness_and_reachability`] if the arm is found to be reachable. + reachable: bool, } impl<'p, 'tcx> PatStack<'p, 'tcx> { - fn from_pattern(pat: &'p DeconstructedPat<'p, 'tcx>, is_under_guard: bool) -> Self { - PatStack { pats: smallvec![pat], is_under_guard } + fn from_pattern( + pat: &'p DeconstructedPat<'p, 'tcx>, + parent_row: usize, + is_under_guard: bool, + ) -> Self { + PatStack { pats: smallvec![pat], parent_row, is_under_guard, reachable: false } } - fn from_vec(vec: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, is_under_guard: bool) -> Self { - PatStack { pats: vec, is_under_guard } + fn from_vec( + pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, + parent_row: usize, + is_under_guard: bool, + ) -> Self { + PatStack { pats, parent_row, is_under_guard, reachable: false } } fn is_empty(&self) -> bool { @@ -417,51 +616,34 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { self.pats.iter().copied() } - // Recursively expand the first pattern into its subpatterns. Only useful if the pattern is an - // or-pattern. Panics if `self` is empty. + // Recursively expand the first or-pattern into its subpatterns. Only useful if the pattern is + // an or-pattern. Panics if `self` is empty. fn expand_or_pat<'a>(&'a self) -> impl Iterator> + Captures<'a> { - self.head().iter_fields().map(move |pat| { - let mut new_patstack = PatStack::from_pattern(pat, self.is_under_guard); + self.head().flatten_or_pat().into_iter().map(move |pat| { + let mut new_patstack = + PatStack::from_pattern(pat, self.parent_row, self.is_under_guard); new_patstack.pats.extend_from_slice(&self.pats[1..]); new_patstack }) } - // Recursively expand all patterns into their subpatterns and push each `PatStack` to matrix. - fn expand_and_extend<'a>(&'a self, matrix: &mut Matrix<'p, 'tcx>) { - if !self.is_empty() && self.head().is_or_pat() { - for pat in self.head().iter_fields() { - let mut new_patstack = PatStack::from_pattern(pat, self.is_under_guard); - new_patstack.pats.extend_from_slice(&self.pats[1..]); - if !new_patstack.is_empty() && new_patstack.head().is_or_pat() { - new_patstack.expand_and_extend(matrix); - } else if !new_patstack.is_empty() { - matrix.push(new_patstack); - } - } - } - } - - /// This computes `S(self.head().ctor(), self)`. See top of the file for explanations. - /// - /// Structure patterns with a partial wild pattern (Foo { a: 42, .. }) have their missing - /// fields filled with wild patterns. - /// - /// This is roughly the inverse of `Constructor::apply`. + /// This computes `specialize(ctor, self)`. See top of the file for explanations. + /// Only call if `ctor.is_covered_by(self.head().ctor())` is true. fn pop_head_constructor( &self, pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>, + parent_row: usize, ) -> PatStack<'p, 'tcx> { // We pop the head pattern and push the new fields extracted from the arguments of // `self.head()`. let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor); new_fields.extend_from_slice(&self.pats[1..]); - PatStack::from_vec(new_fields, self.is_under_guard) + PatStack::from_vec(new_fields, parent_row, self.is_under_guard) } } -/// Pretty-printing for matrix row. +/// Pretty-printing for a matrix row. impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { write!(f, "+")?; @@ -472,51 +654,82 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { } } -/// A 2D matrix. +/// A 2D matrix. Represents a list of pattern-tuples under investigation. +/// +/// Invariant: each row must have the same length, and each column must have the same type. +/// +/// Invariant: the first column must not contain or-patterns. This is handled by +/// [`Matrix::expand_and_push`]. +/// +/// In fact each column corresponds to a place inside the scrutinee of the match. E.g. after +/// specializing `(,)` and `Some` on a pattern of type `(Option, bool)`, the first column of +/// the matrix will correspond to `scrutinee.0.Some.0` and the second column to `scrutinee.1`. #[derive(Clone)] -pub(super) struct Matrix<'p, 'tcx> { - pub rows: Vec>, +struct Matrix<'p, 'tcx> { + rows: Vec>, } impl<'p, 'tcx> Matrix<'p, 'tcx> { + /// Make an empty matrix. Internal method, prefer [`Matrix::new`]. fn empty() -> Self { Matrix { rows: vec![] } } - /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively - /// expands it. + /// expands it. Internal method, prefer [`Matrix::new`]. fn push(&mut self, row: PatStack<'p, 'tcx>) { if !row.is_empty() && row.head().is_or_pat() { - row.expand_and_extend(self); + // Expand nested or-patterns. + for new_row in row.expand_or_pat() { + self.rows.push(new_row); + } } else { self.rows.push(row); } } + /// Build a new matrix from an iterator of `MatchArm`s. + fn new<'a>(iter: impl Iterator>) -> Self + where + 'p: 'a, + { + let mut matrix = Matrix::empty(); + for (row_id, arm) in iter.enumerate() { + let v = PatStack::from_pattern(arm.pat, row_id, arm.has_guard); + matrix.push(v); + } + matrix + } + fn rows<'a>( &'a self, ) -> impl Iterator> + Clone + DoubleEndedIterator + ExactSizeIterator { self.rows.iter() } + fn rows_mut<'a>( + &'a mut self, + ) -> impl Iterator> + DoubleEndedIterator + ExactSizeIterator + { + self.rows.iter_mut() + } - /// Iterate over the first component of each row + /// Iterate over the first pattern of each row. fn heads<'a>( &'a self, ) -> impl Iterator> + Clone + Captures<'a> { self.rows().map(|r| r.head()) } - /// This computes `S(constructor, self)`. See top of the file for explanations. + /// This computes `specialize(ctor, self)`. See top of the file for explanations. fn specialize_constructor( &self, pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>, ) -> Matrix<'p, 'tcx> { let mut matrix = Matrix::empty(); - for row in &self.rows { + for (i, row) in self.rows().enumerate() { if ctor.is_covered_by(pcx, row.head().ctor()) { - let new_row = row.pop_head_constructor(pcx, ctor); + let new_row = row.pop_head_constructor(pcx, ctor, i); matrix.push(new_row); } } @@ -560,92 +773,17 @@ impl<'p, 'tcx> fmt::Debug for Matrix<'p, 'tcx> { } } -/// This carries the results of computing usefulness, as described at the top of the file. When -/// checking usefulness of a match branch, we use the `NoWitnesses` variant, which also keeps track -/// of potential unreachable sub-patterns (in the presence of or-patterns). When checking -/// exhaustiveness of a whole match, we use the `WithWitnesses` variant, which carries a list of -/// witnesses of non-exhaustiveness when there are any. -/// Which variant to use is dictated by `ArmType`. -#[derive(Debug, Clone)] -enum Usefulness<'tcx> { - /// If we don't care about witnesses, simply remember if the pattern was useful. - NoWitnesses { useful: bool }, - /// Carries a list of witnesses of non-exhaustiveness. If empty, indicates that the whole - /// pattern is unreachable. - WithWitnesses(WitnessMatrix<'tcx>), -} - -impl<'tcx> Usefulness<'tcx> { - fn new_useful(preference: ArmType) -> Self { - match preference { - // A single (empty) witness of reachability. - FakeExtraWildcard => WithWitnesses(WitnessMatrix::unit_witness()), - RealArm => NoWitnesses { useful: true }, - } - } - - fn new_not_useful(preference: ArmType) -> Self { - match preference { - FakeExtraWildcard => WithWitnesses(WitnessMatrix::empty()), - RealArm => NoWitnesses { useful: false }, - } - } - - fn is_useful(&self) -> bool { - match self { - Usefulness::NoWitnesses { useful } => *useful, - Usefulness::WithWitnesses(witnesses) => !witnesses.is_empty(), - } - } - - /// Combine usefulnesses from two branches. This is an associative operation. - fn extend(&mut self, other: Self) { - match (&mut *self, other) { - (WithWitnesses(_), WithWitnesses(o)) if o.is_empty() => {} - (WithWitnesses(s), WithWitnesses(o)) if s.is_empty() => *self = WithWitnesses(o), - (WithWitnesses(s), WithWitnesses(o)) => s.extend(o), - (NoWitnesses { useful: s_useful }, NoWitnesses { useful: o_useful }) => { - *s_useful = *s_useful || o_useful - } - _ => unreachable!(), - } - } - - /// After calculating usefulness after a specialization, call this to reconstruct a usefulness - /// that makes sense for the matrix pre-specialization. This new usefulness can then be merged - /// with the results of specializing with the other constructors. - fn apply_constructor( - mut self, - pcx: &PatCtxt<'_, '_, 'tcx>, - matrix: &Matrix<'_, 'tcx>, // used to compute missing ctors - ctor: &Constructor<'tcx>, - ) -> Self { - match &mut self { - NoWitnesses { .. } => {} - WithWitnesses(witnesses) => witnesses.apply_constructor(pcx, matrix, ctor), - } - self - } -} - -#[derive(Copy, Clone, Debug)] -enum ArmType { - FakeExtraWildcard, - RealArm, -} - -/// A partially-constructed witness of non-exhaustiveness for error reporting, represented as a list -/// of patterns (in reverse order of construction) with wildcards inside to represent elements that -/// can take any inhabitant of the type as a value. +/// A witness-tuple of non-exhaustiveness for error reporting, represented as a list of patterns (in +/// reverse order of construction). /// /// This mirrors `PatStack`: they function similarly, except `PatStack` contains user patterns we /// are inspecting, and `WitnessStack` contains witnesses we are constructing. -/// FIXME(Nadrieril): use the same order of patterns for both +/// FIXME(Nadrieril): use the same order of patterns for both. /// -/// A `WitnessStack` should have the same types and length as the `PatStacks` we are inspecting -/// (except we store the patterns in reverse order). Because Rust `match` is always against a single -/// pattern, at the end the stack will have length 1. In the middle of the algorithm, it can contain -/// multiple patterns. +/// A `WitnessStack` should have the same types and length as the `PatStack`s we are inspecting +/// (except we store the patterns in reverse order). The same way `PatStack` starts with length 1, +/// at the end of the algorithm this will have length 1. In the middle of the algorithm, it can +/// contain multiple patterns. /// /// For example, if we are constructing a witness for the match against /// @@ -660,6 +798,7 @@ enum ArmType { /// ``` /// /// We'll perform the following steps (among others): +/// ```text /// - Start with a matrix representing the match /// `PatStack(vec![Pair(None, _)])` /// `PatStack(vec![Pair(_, false)])` @@ -682,8 +821,11 @@ enum ArmType { /// `WitnessStack(vec![true, Some(_)])` /// - Apply `Pair` /// `WitnessStack(vec![Pair(Some(_), true)])` +/// ``` /// /// The final `Pair(Some(_), true)` is then the resulting witness. +/// +/// See the top of the file for more detailed explanations and examples. #[derive(Debug, Clone)] pub(crate) struct WitnessStack<'tcx>(Vec>); @@ -700,8 +842,11 @@ impl<'tcx> WitnessStack<'tcx> { } /// Reverses specialization. Given a witness obtained after specialization, this constructs a - /// new witness valid for before specialization. Examples: + /// new witness valid for before specialization. See the section on `unspecialize` at the top of + /// the file. /// + /// Examples: + /// ```text /// ctor: tuple of 2 elements /// pats: [false, "foo", _, true] /// result: [(false, "foo"), _, true] @@ -709,6 +854,7 @@ impl<'tcx> WitnessStack<'tcx> { /// ctor: Enum::Variant { a: (bool, &'static str), b: usize} /// pats: [(false, "foo"), _, true] /// result: [Enum::Variant { a: (false, "foo"), b: _ }, true] + /// ``` fn apply_constructor(&mut self, pcx: &PatCtxt<'_, '_, 'tcx>, ctor: &Constructor<'tcx>) { let len = self.0.len(); let arity = ctor.arity(pcx); @@ -718,26 +864,29 @@ impl<'tcx> WitnessStack<'tcx> { } } -/// Represents a set of partially-constructed witnesses of non-exhaustiveness for error reporting. -/// This has similar invariants as `Matrix` does. -/// Throughout the exhaustiveness phase of the algorithm, `is_useful` maintains the invariant that -/// the union of the `Matrix` and the `WitnessMatrix` together matches the type exhaustively. By the -/// end of the algorithm, this has a single column, which contains the patterns that are missing for -/// the match to be exhaustive. +/// Represents a set of pattern-tuples that are witnesses of non-exhaustiveness for error +/// reporting. This has similar invariants as `Matrix` does. +/// +/// The `WitnessMatrix` returned by [`compute_exhaustiveness_and_reachability`] obeys the invariant +/// that the union of the input `Matrix` and the output `WitnessMatrix` together matches the type +/// exhaustively. +/// +/// Just as the `Matrix` starts with a single column, by the end of the algorithm, this has a single +/// column, which contains the patterns that are missing for the match to be exhaustive. #[derive(Debug, Clone)] pub struct WitnessMatrix<'tcx>(Vec>); impl<'tcx> WitnessMatrix<'tcx> { - /// New matrix with no rows. + /// New matrix with no witnesses. fn empty() -> Self { WitnessMatrix(vec![]) } - /// New matrix with one row and no columns. + /// New matrix with one `()` witness, i.e. with no columns. fn unit_witness() -> Self { WitnessMatrix(vec![WitnessStack(vec![])]) } - /// Whether this has any rows. + /// Whether this has any witnesses. fn is_empty(&self) -> bool { self.0.is_empty() } @@ -753,19 +902,20 @@ impl<'tcx> WitnessMatrix<'tcx> { } } - /// Reverses specialization by `ctor`. + /// Reverses specialization by `ctor`. See the section on `unspecialize` at the top of the file. fn apply_constructor( &mut self, pcx: &PatCtxt<'_, '_, 'tcx>, - matrix: &Matrix<'_, 'tcx>, // used to compute missing ctors + missing_ctors: &[Constructor<'tcx>], ctor: &Constructor<'tcx>, ) { if self.is_empty() { return; } - if matches!(ctor, Constructor::Missing { .. }) { - let missing_ctors = ConstructorSet::for_ty(pcx.cx, pcx.ty) - .compute_missing(pcx, matrix.heads().map(DeconstructedPat::ctor)); + if matches!(ctor, Constructor::Wildcard) { + let pat = WitnessPat::wild_from_ctor(pcx, Constructor::Wildcard); + self.push_pattern(&pat); + } else if matches!(ctor, Constructor::Missing) { // We got the special `Missing` constructor, so each of the missing constructors gives a // new pattern that is not caught by the match. We list those patterns and push them // onto our current witnesses. @@ -782,6 +932,12 @@ impl<'tcx> WitnessMatrix<'tcx> { self.extend(witnesses_with_missing_ctor) } } + } else if !missing_ctors.is_empty() { + // `ctor` isn't `Wildcard` or `Missing` and some ctors are missing, so we know + // `split_ctors` will contain `Wildcard` or `Missing`. + // For diagnostic purposes we choose to discard witnesses we got under `ctor`, which + // will let only the `Wildcard` or `Missing` be reported. + self.0.clear(); } else { for witness in self.0.iter_mut() { witness.apply_constructor(pcx, ctor) @@ -789,123 +945,129 @@ impl<'tcx> WitnessMatrix<'tcx> { } } - /// Merges the rows of two witness matrices. Their column types must match. + /// Merges the witnesses of two matrices. Their column types must match. fn extend(&mut self, other: Self) { self.0.extend(other.0) } } -/// Algorithm from . -/// The algorithm from the paper has been modified to correctly handle empty -/// types. The changes are: -/// (0) We don't exit early if the pattern matrix has zero rows. We just -/// continue to recurse over columns. -/// (1) all_constructors will only return constructors that are statically -/// possible. E.g., it will only return `Ok` for `Result`. +/// The core of the algorithm. /// -/// This finds whether a (row) vector `v` of patterns is 'useful' in relation -/// to a set of such vectors `m` - this is defined as there being a set of -/// inputs that will match `v` but not any of the sets in `m`. +/// This recursively computes witnesses of the non-exhaustiveness of `matrix` (if any). Also tracks +/// usefulness of each row in the matrix (in `row.reachable`). We track reachability of each +/// subpattern using interior mutability in `DeconstructedPat`. /// -/// All the patterns at each column of the `matrix ++ v` matrix must have the same type. +/// The input `Matrix` and the output `WitnessMatrix` together match the type exhaustively. /// -/// This is used both for reachability checking (if a pattern isn't useful in -/// relation to preceding patterns, it is not reachable) and exhaustiveness -/// checking (if a wildcard pattern is useful in relation to a matrix, the -/// matrix isn't exhaustive). +/// The key steps are: +/// - specialization, where we dig into the rows that have a specific constructor and call ourselves +/// recursively; +/// - unspecialization, where we lift the results from the previous step into results for this step +/// (using `apply_constructor` and by updating `row.reachable` for each parent row). +/// This is all explained at the top of the file. /// -/// `is_under_guard` is used to inform if the pattern has a guard. If it -/// has one it must not be inserted into the matrix. This shouldn't be -/// relied on for soundness. -#[instrument(level = "debug", skip(cx, matrix, lint_root), ret)] -fn is_useful<'p, 'tcx>( +/// `wildcard_row` is a fictitious matrix row that has only wildcards, with the appropriate types to +/// match what's in the columns of `matrix`. +#[instrument(level = "debug", skip(cx, is_top_level), ret)] +fn compute_exhaustiveness_and_reachability<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, - matrix: &Matrix<'p, 'tcx>, - v: &PatStack<'p, 'tcx>, - witness_preference: ArmType, - lint_root: HirId, + matrix: &mut Matrix<'p, 'tcx>, + wildcard_row: &PatStack<'p, 'tcx>, is_top_level: bool, -) -> Usefulness<'tcx> { - debug!(?matrix, ?v); - // The base case. We are pattern-matching on () and the return value is - // based on whether our matrix has a row or not. - // NOTE: This could potentially be optimized by checking rows.is_empty() - // first and then, if v is non-empty, the return value is based on whether - // the type of the tuple we're checking is inhabited or not. - if v.is_empty() { - let ret = if matrix.rows().all(|r| r.is_under_guard) { - Usefulness::new_useful(witness_preference) - } else { - Usefulness::new_not_useful(witness_preference) - }; - debug!(?ret); - return ret; - } +) -> WitnessMatrix<'tcx> { + debug_assert!(matrix.rows().all(|r| r.len() == wildcard_row.len())); - debug_assert!(matrix.rows().all(|r| r.len() == v.len())); - - // If the first pattern is an or-pattern, expand it. - let mut ret = Usefulness::new_not_useful(witness_preference); - if v.head().is_or_pat() { - debug!("expanding or-pattern"); - // We try each or-pattern branch in turn. - let mut matrix = matrix.clone(); - for v in v.expand_or_pat() { - debug!(?v); - let usefulness = ensure_sufficient_stack(|| { - is_useful(cx, &matrix, &v, witness_preference, lint_root, false) - }); - debug!(?usefulness); - ret.extend(usefulness); - // We push the already-seen patterns into the matrix in order to detect redundant - // branches like `Some(_) | Some(0)`. - matrix.push(v); - } - } else { - let mut ty = v.head().ty(); - - // Opaque types can't get destructured/split, but the patterns can - // actually hint at hidden types, so we use the patterns' types instead. - if let ty::Alias(ty::Opaque, ..) = ty.kind() { - if let Some(row) = matrix.rows().next() { - ty = row.head().ty(); + if wildcard_row.is_empty() { + // The base case. We are morally pattern-matching on (). A row is reachable iff it has no + // (unguarded) rows above it. + for row in matrix.rows_mut() { + // All rows are reachable until we find one without a guard. + row.reachable = true; + if !row.is_under_guard { + // There's an unguarded row, so the match is exhaustive, and any subsequent row is + // unreachable. + return WitnessMatrix::empty(); } } - debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span()); - let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level }; + // No (unguarded) rows, so the match is not exhaustive. We return a new witness. + return WitnessMatrix::unit_witness(); + } - let v_ctor = v.head().ctor(); - debug!(?v_ctor); - // We split the head constructor of `v`. - let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - // For each constructor, we compute whether there's a value that starts with it that would - // witness the usefulness of `v`. - let start_matrix = &matrix; - for ctor in split_ctors { - debug!("specialize({:?})", ctor); - // We cache the result of `Fields::wildcards` because it is used a lot. - let spec_matrix = start_matrix.specialize_constructor(pcx, &ctor); - let v = v.pop_head_constructor(pcx, &ctor); - let usefulness = ensure_sufficient_stack(|| { - is_useful(cx, &spec_matrix, &v, witness_preference, lint_root, false) - }); - let usefulness = usefulness.apply_constructor(pcx, start_matrix, &ctor); - ret.extend(usefulness); + let mut ty = wildcard_row.head().ty(); + // If the type is opaque and it is revealed anywhere in the column, we take the revealed + // version. Otherwise we could encounter constructors for the revealed type and crash. + let is_opaque = |ty: Ty<'tcx>| matches!(ty.kind(), ty::Alias(ty::Opaque, ..)); + if is_opaque(ty) { + for pat in matrix.heads() { + let pat_ty = pat.ty(); + if !is_opaque(pat_ty) { + ty = pat_ty; + break; + } } } - if ret.is_useful() { - v.head().set_reachable(); + debug!("ty: {ty:?}"); + let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level }; + + // Analyze the constructors present in this column. + let ctors = matrix.heads().map(|p| p.ctor()); + let split_set = ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, ctors); + let mut split_ctors = split_set.present; + // We want to iterate over a full set of constructors, so if any is missing we add a wildcard. + if !split_set.missing.is_empty() { + let all_missing = split_ctors.is_empty(); + let always_report_missing = is_top_level && !IntRange::is_integral(pcx.ty); + let ctor = if all_missing && !always_report_missing { + Constructor::Wildcard + } else { + // Like `Wildcard`, except if it doesn't match a row this will report all the missing + // constructors instead of just `_`. + Constructor::Missing + }; + split_ctors.push(ctor); } + let mut ret = WitnessMatrix::empty(); + for ctor in split_ctors { + debug!("specialize({:?})", ctor); + // Dig into rows that match `ctor`. + let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor); + let wildcard_row = wildcard_row.pop_head_constructor(pcx, &ctor, usize::MAX); + let mut witnesses = ensure_sufficient_stack(|| { + compute_exhaustiveness_and_reachability(cx, &mut spec_matrix, &wildcard_row, false) + }); + // Transform witnesses for `spec_matrix` into witnesses for `matrix`. + witnesses.apply_constructor(pcx, &split_set.missing, &ctor); + ret.extend(witnesses); + + // A parent row is useful if any of its children is. + for child_row in spec_matrix.rows() { + let parent_row = &mut matrix.rows[child_row.parent_row]; + parent_row.reachable = parent_row.reachable || child_row.reachable; + } + } + + // Record that the subpattern is reachable. + for row in matrix.rows() { + if row.reachable { + row.head().set_reachable(); + } + } ret } /// A column of patterns in the matrix, where a column is the intuitive notion of "subpatterns that -/// inspect the same subvalue". +/// inspect the same subvalue/place". /// This is used to traverse patterns column-by-column for lints. Despite similarities with -/// `is_useful`, this is a different traversal. Notably this is linear in the depth of patterns, -/// whereas `is_useful` is worst-case exponential (exhaustiveness is NP-complete). +/// [`compute_exhaustiveness_and_reachability`], this does a different traversal. Notably this is +/// linear in the depth of patterns, whereas `compute_exhaustiveness_and_reachability` is worst-case +/// exponential (exhaustiveness is NP-complete). The core difference is that we treat sub-columns +/// separately. +/// +/// This must not contain an or-pattern. `specialize` takes care to expand them. +/// +/// This is not used in the main algorithm; only in lints. #[derive(Debug)] struct PatternColumn<'p, 'tcx> { patterns: Vec<&'p DeconstructedPat<'p, 'tcx>>, @@ -938,17 +1100,19 @@ impl<'p, 'tcx> PatternColumn<'p, 'tcx> { Some(first_ty) } + /// Do constructor splitting on the constructors of the column. fn analyze_ctors(&self, pcx: &PatCtxt<'_, 'p, 'tcx>) -> SplitConstructorSet<'tcx> { let column_ctors = self.patterns.iter().map(|p| p.ctor()); ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, column_ctors) } + fn iter<'a>(&'a self) -> impl Iterator> + Captures<'a> { self.patterns.iter().copied() } /// Does specialization: given a constructor, this takes the patterns from the column that match /// the constructor, and outputs their fields. - /// This returns one column per field of the constructor. The normally all have the same length + /// This returns one column per field of the constructor. They usually all have the same length /// (the number of patterns in `self` that matched `ctor`), except that we expand or-patterns /// which may change the lengths. fn specialize(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>) -> Vec { @@ -1138,11 +1302,8 @@ pub(crate) struct UsefulnessReport<'p, 'tcx> { pub(crate) non_exhaustiveness_witnesses: Vec>, } -/// The entrypoint for the usefulness algorithm. Computes whether a match is exhaustive and which -/// of its arms are reachable. -/// -/// Note: the input patterns must have been lowered through -/// `check_match::MatchVisitor::lower_pattern`. +/// The entrypoint for this file. Computes whether a match is exhaustive and which of its arms are +/// reachable. #[instrument(skip(cx, arms), level = "debug")] pub(crate) fn compute_match_usefulness<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, @@ -1151,15 +1312,18 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( scrut_ty: Ty<'tcx>, scrut_span: Span, ) -> UsefulnessReport<'p, 'tcx> { - let mut matrix = Matrix::empty(); + let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP)); + let wildcard_row = PatStack::from_pattern(wild_pattern, usize::MAX, false); + let mut matrix = Matrix::new(arms.iter()); + let non_exhaustiveness_witnesses = + compute_exhaustiveness_and_reachability(cx, &mut matrix, &wildcard_row, true); + + let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column(); let arm_usefulness: Vec<_> = arms .iter() .copied() .map(|arm| { debug!(?arm); - let v = PatStack::from_pattern(arm.pat, arm.has_guard); - is_useful(cx, &matrix, &v, RealArm, arm.hir_id, true); - matrix.push(v); let reachability = if arm.pat.is_reachable() { Reachability::Reachable(arm.pat.unreachable_spans()) } else { @@ -1168,28 +1332,20 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( (arm, reachability) }) .collect(); + let report = UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses }; - let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP)); - let v = PatStack::from_pattern(wild_pattern, false); - let usefulness = is_useful(cx, &matrix, &v, FakeExtraWildcard, lint_root, true); - let non_exhaustiveness_witnesses: Vec<_> = match usefulness { - WithWitnesses(witness_matrix) => witness_matrix.single_column(), - NoWitnesses { .. } => bug!(), - }; - - let pat_column = arms.iter().flat_map(|arm| arm.pat.flatten_or_pat()).collect::>(); - let pat_column = PatternColumn::new(pat_column); + let pat_column = PatternColumn::new(matrix.heads().collect()); + // Lint on ranges that overlap on their endpoints, which is likely a mistake. lint_overlapping_range_endpoints(cx, &pat_column, lint_root); // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting // `if let`s. Only run if the match is exhaustive otherwise the error is redundant. - if cx.refutable && non_exhaustiveness_witnesses.is_empty() { + if cx.refutable && report.non_exhaustiveness_witnesses.is_empty() { if !matches!( cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, lint_root).0, rustc_session::lint::Level::Allow ) { let witnesses = collect_nonexhaustive_missing_variants(cx, &pat_column); - if !witnesses.is_empty() { // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` // is not exhaustive enough. @@ -1230,5 +1386,5 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( } } - UsefulnessReport { arm_usefulness, non_exhaustiveness_witnesses } + report } diff --git a/tests/ui/pattern/usefulness/integer-ranges/reachability.rs b/tests/ui/pattern/usefulness/integer-ranges/reachability.rs index fb4d59b05780..247fdd91572c 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/reachability.rs +++ b/tests/ui/pattern/usefulness/integer-ranges/reachability.rs @@ -9,9 +9,10 @@ macro_rules! m { $t2 => {} _ => {} } - } + }; } +#[rustfmt::skip] fn main() { m!(0u8, 42, 41); m!(0u8, 42, 42); //~ ERROR unreachable pattern @@ -85,7 +86,7 @@ fn main() { match 'a' { '\u{0}'..='\u{D7FF}' => {}, '\u{E000}'..='\u{10_FFFF}' => {}, - '\u{D7FF}'..='\u{E000}' => {}, // FIXME should be unreachable + '\u{D7FF}'..='\u{E000}' => {}, //~ ERROR unreachable pattern } match (0u8, true) { diff --git a/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr b/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr index 0ffb0ffd82aa..c5b028d2038c 100644 --- a/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr +++ b/tests/ui/pattern/usefulness/integer-ranges/reachability.stderr @@ -1,5 +1,5 @@ error: unreachable pattern - --> $DIR/reachability.rs:17:17 + --> $DIR/reachability.rs:18:17 | LL | m!(0u8, 42, 42); | ^^ @@ -11,127 +11,127 @@ LL | #![deny(unreachable_patterns)] | ^^^^^^^^^^^^^^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:21:22 + --> $DIR/reachability.rs:22:22 | LL | m!(0u8, 20..=30, 20); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:22:22 + --> $DIR/reachability.rs:23:22 | LL | m!(0u8, 20..=30, 21); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:23:22 + --> $DIR/reachability.rs:24:22 | LL | m!(0u8, 20..=30, 25); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:24:22 + --> $DIR/reachability.rs:25:22 | LL | m!(0u8, 20..=30, 29); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:25:22 + --> $DIR/reachability.rs:26:22 | LL | m!(0u8, 20..=30, 30); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:28:21 + --> $DIR/reachability.rs:29:21 | LL | m!(0u8, 20..30, 20); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:29:21 + --> $DIR/reachability.rs:30:21 | LL | m!(0u8, 20..30, 21); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:30:21 + --> $DIR/reachability.rs:31:21 | LL | m!(0u8, 20..30, 25); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:31:21 + --> $DIR/reachability.rs:32:21 | LL | m!(0u8, 20..30, 29); | ^^ error: unreachable pattern - --> $DIR/reachability.rs:35:22 + --> $DIR/reachability.rs:36:22 | LL | m!(0u8, 20..=30, 20..=30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:36:22 + --> $DIR/reachability.rs:37:22 | LL | m!(0u8, 20.. 30, 20.. 30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:37:22 + --> $DIR/reachability.rs:38:22 | LL | m!(0u8, 20..=30, 20.. 30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:39:22 + --> $DIR/reachability.rs:40:22 | LL | m!(0u8, 20..=30, 21..=30); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:40:22 + --> $DIR/reachability.rs:41:22 | LL | m!(0u8, 20..=30, 20..=29); | ^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:42:24 + --> $DIR/reachability.rs:43:24 | LL | m!('a', 'A'..='z', 'a'..='z'); | ^^^^^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:49:9 + --> $DIR/reachability.rs:50:9 | LL | 5..=8 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:55:9 + --> $DIR/reachability.rs:56:9 | LL | 5..15 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:62:9 + --> $DIR/reachability.rs:63:9 | LL | 5..25 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:70:9 + --> $DIR/reachability.rs:71:9 | LL | 5..25 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:76:9 + --> $DIR/reachability.rs:77:9 | LL | 5..15 => {}, | ^^^^^ error: unreachable pattern - --> $DIR/reachability.rs:83:9 + --> $DIR/reachability.rs:84:9 | LL | _ => {}, | - matches any value @@ -139,16 +139,22 @@ LL | '\u{D7FF}'..='\u{E000}' => {}, | ^^^^^^^^^^^^^^^^^^^^^^^ unreachable pattern error: unreachable pattern - --> $DIR/reachability.rs:104:9 + --> $DIR/reachability.rs:89:9 + | +LL | '\u{D7FF}'..='\u{E000}' => {}, + | ^^^^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/reachability.rs:105:9 | LL | &FOO => {} | ^^^^ error: unreachable pattern - --> $DIR/reachability.rs:105:9 + --> $DIR/reachability.rs:106:9 | LL | BAR => {} | ^^^ -error: aborting due to 24 previous errors +error: aborting due to 25 previous errors From fd0d8834c2e09a6f26d4c6eff5531659818f2d91 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 5 Nov 2023 14:52:26 +0100 Subject: [PATCH 23/93] Store wildcard row in the matrix --- .../src/thir/pattern/usefulness.rs | 87 ++++++++++--------- 1 file changed, 48 insertions(+), 39 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 3819a6a95c21..29d1a58cb689 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -667,16 +667,15 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { #[derive(Clone)] struct Matrix<'p, 'tcx> { rows: Vec>, + /// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of + /// each column. This must obey the same invariants as the real rows. + wildcard_row: PatStack<'p, 'tcx>, } impl<'p, 'tcx> Matrix<'p, 'tcx> { - /// Make an empty matrix. Internal method, prefer [`Matrix::new`]. - fn empty() -> Self { - Matrix { rows: vec![] } - } /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively /// expands it. Internal method, prefer [`Matrix::new`]. - fn push(&mut self, row: PatStack<'p, 'tcx>) { + fn expand_and_push(&mut self, row: PatStack<'p, 'tcx>) { if !row.is_empty() && row.head().is_or_pat() { // Expand nested or-patterns. for new_row in row.expand_or_pat() { @@ -688,18 +687,48 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { } /// Build a new matrix from an iterator of `MatchArm`s. - fn new<'a>(iter: impl Iterator>) -> Self + fn new<'a>( + cx: &MatchCheckCtxt<'p, 'tcx>, + iter: impl Iterator>, + scrut_ty: Ty<'tcx>, + ) -> Self where 'p: 'a, { - let mut matrix = Matrix::empty(); + let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP)); + let wildcard_row = PatStack::from_pattern(wild_pattern, usize::MAX, false); + let mut matrix = Matrix { rows: vec![], wildcard_row }; for (row_id, arm) in iter.enumerate() { let v = PatStack::from_pattern(arm.pat, row_id, arm.has_guard); - matrix.push(v); + matrix.expand_and_push(v); } matrix } + fn head_ty(&self) -> Option> { + if self.column_count() == 0 { + return None; + } + + let mut ty = self.wildcard_row.head().ty(); + // If the type is opaque and it is revealed anywhere in the column, we take the revealed + // version. Otherwise we could encounter constructors for the revealed type and crash. + let is_opaque = |ty: Ty<'tcx>| matches!(ty.kind(), ty::Alias(ty::Opaque, ..)); + if is_opaque(ty) { + for pat in self.heads() { + let pat_ty = pat.ty(); + if !is_opaque(pat_ty) { + ty = pat_ty; + break; + } + } + } + Some(ty) + } + fn column_count(&self) -> usize { + self.wildcard_row.len() + } + fn rows<'a>( &'a self, ) -> impl Iterator> + Clone + DoubleEndedIterator + ExactSizeIterator @@ -726,11 +755,12 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>, ) -> Matrix<'p, 'tcx> { - let mut matrix = Matrix::empty(); + let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor, usize::MAX); + let mut matrix = Matrix { rows: vec![], wildcard_row }; for (i, row) in self.rows().enumerate() { if ctor.is_covered_by(pcx, row.head().ctor()) { let new_row = row.pop_head_constructor(pcx, ctor, i); - matrix.push(new_row); + matrix.expand_and_push(new_row); } } matrix @@ -965,21 +995,17 @@ impl<'tcx> WitnessMatrix<'tcx> { /// - unspecialization, where we lift the results from the previous step into results for this step /// (using `apply_constructor` and by updating `row.reachable` for each parent row). /// This is all explained at the top of the file. -/// -/// `wildcard_row` is a fictitious matrix row that has only wildcards, with the appropriate types to -/// match what's in the columns of `matrix`. #[instrument(level = "debug", skip(cx, is_top_level), ret)] fn compute_exhaustiveness_and_reachability<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, matrix: &mut Matrix<'p, 'tcx>, - wildcard_row: &PatStack<'p, 'tcx>, is_top_level: bool, ) -> WitnessMatrix<'tcx> { - debug_assert!(matrix.rows().all(|r| r.len() == wildcard_row.len())); + debug_assert!(matrix.rows().all(|r| r.len() == matrix.column_count())); - if wildcard_row.is_empty() { - // The base case. We are morally pattern-matching on (). A row is reachable iff it has no - // (unguarded) rows above it. + let Some(ty) = matrix.head_ty() else { + // The base case: there are no columns in the matrix. We are morally pattern-matching on (). + // A row is reachable iff it has no (unguarded) rows above it. for row in matrix.rows_mut() { // All rows are reachable until we find one without a guard. row.reachable = true; @@ -991,21 +1017,7 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>( } // No (unguarded) rows, so the match is not exhaustive. We return a new witness. return WitnessMatrix::unit_witness(); - } - - let mut ty = wildcard_row.head().ty(); - // If the type is opaque and it is revealed anywhere in the column, we take the revealed - // version. Otherwise we could encounter constructors for the revealed type and crash. - let is_opaque = |ty: Ty<'tcx>| matches!(ty.kind(), ty::Alias(ty::Opaque, ..)); - if is_opaque(ty) { - for pat in matrix.heads() { - let pat_ty = pat.ty(); - if !is_opaque(pat_ty) { - ty = pat_ty; - break; - } - } - } + }; debug!("ty: {ty:?}"); let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level }; @@ -1033,9 +1045,8 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>( debug!("specialize({:?})", ctor); // Dig into rows that match `ctor`. let mut spec_matrix = matrix.specialize_constructor(pcx, &ctor); - let wildcard_row = wildcard_row.pop_head_constructor(pcx, &ctor, usize::MAX); let mut witnesses = ensure_sufficient_stack(|| { - compute_exhaustiveness_and_reachability(cx, &mut spec_matrix, &wildcard_row, false) + compute_exhaustiveness_and_reachability(cx, &mut spec_matrix, false) }); // Transform witnesses for `spec_matrix` into witnesses for `matrix`. witnesses.apply_constructor(pcx, &split_set.missing, &ctor); @@ -1312,11 +1323,9 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( scrut_ty: Ty<'tcx>, scrut_span: Span, ) -> UsefulnessReport<'p, 'tcx> { - let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP)); - let wildcard_row = PatStack::from_pattern(wild_pattern, usize::MAX, false); - let mut matrix = Matrix::new(arms.iter()); + let mut matrix = Matrix::new(cx, arms.iter(), scrut_ty); let non_exhaustiveness_witnesses = - compute_exhaustiveness_and_reachability(cx, &mut matrix, &wildcard_row, true); + compute_exhaustiveness_and_reachability(cx, &mut matrix, true); let non_exhaustiveness_witnesses: Vec<_> = non_exhaustiveness_witnesses.single_column(); let arm_usefulness: Vec<_> = arms From 0edb8791676aefd0a8dc1f118177a34c70be24ce Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 5 Nov 2023 15:25:15 +0100 Subject: [PATCH 24/93] Cleanup span passing --- .../src/thir/pattern/check_match.rs | 13 +++++--- .../src/thir/pattern/deconstruct_pat.rs | 17 +++++----- .../src/thir/pattern/usefulness.rs | 31 +++++++++---------- 3 files changed, 31 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index d1a2772c6554..e402468f038e 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -291,6 +291,7 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> { &self, refutability: RefutableFlag, match_span: Option, + scrut_span: Span, ) -> MatchCheckCtxt<'p, 'tcx> { let refutable = match refutability { Irrefutable => false, @@ -301,7 +302,9 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> { param_env: self.param_env, module: self.tcx.parent_module(self.lint_level).to_def_id(), pattern_arena: self.pattern_arena, + match_lint_level: self.lint_level, match_span, + scrut_span, refutable, } } @@ -332,7 +335,8 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> { source: hir::MatchSource, expr_span: Span, ) { - let cx = self.new_cx(Refutable, Some(expr_span)); + let scrut = &self.thir[scrut]; + let cx = self.new_cx(Refutable, Some(expr_span), scrut.span); let mut tarms = Vec::with_capacity(arms.len()); for &arm in arms { @@ -348,9 +352,8 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> { } } - let scrut = &self.thir[scrut]; let scrut_ty = scrut.ty; - let report = compute_match_usefulness(&cx, &tarms, self.lint_level, scrut_ty, scrut.span); + let report = compute_match_usefulness(&cx, &tarms, scrut_ty); match source { // Don't report arm reachability of desugared `match $iter.into_iter() { iter => .. }` @@ -455,10 +458,10 @@ impl<'thir, 'p, 'tcx> MatchVisitor<'thir, 'p, 'tcx> { pat: &Pat<'tcx>, refutability: RefutableFlag, ) -> Result<(MatchCheckCtxt<'p, 'tcx>, UsefulnessReport<'p, 'tcx>), ErrorGuaranteed> { - let cx = self.new_cx(refutability, None); + let cx = self.new_cx(refutability, None, pat.span); let pat = self.lower_pattern(&cx, pat)?; let arms = [MatchArm { pat, hir_id: self.lint_level, has_guard: false }]; - let report = compute_match_usefulness(&cx, &arms, self.lint_level, pat.ty(), pat.span()); + let report = compute_match_usefulness(&cx, &arms, pat.ty()); Ok((cx, report)) } diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index 8c864c9f2ec7..a4c1d20f454c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -848,7 +848,7 @@ impl<'tcx> Constructor<'tcx> { (Opaque(..), _) | (_, Opaque(..)) => false, _ => span_bug!( - pcx.span, + pcx.cx.scrut_span, "trying to compare incompatible constructors {:?} and {:?}", self, other @@ -1249,9 +1249,8 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { fn wildcards_from_tys( cx: &MatchCheckCtxt<'p, 'tcx>, tys: impl IntoIterator>, - span: Span, ) -> Self { - Fields::from_iter(cx, tys.into_iter().map(|ty| DeconstructedPat::wildcard(ty, span))) + Fields::from_iter(cx, tys.into_iter().map(|ty| DeconstructedPat::wildcard(ty, DUMMY_SP))) } // In the cases of either a `#[non_exhaustive]` field list or a non-public field, we hide @@ -1287,18 +1286,18 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { pub(super) fn wildcards(pcx: &PatCtxt<'_, 'p, 'tcx>, constructor: &Constructor<'tcx>) -> Self { let ret = match constructor { Single | Variant(_) => match pcx.ty.kind() { - ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter(), pcx.span), - ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty), pcx.span), + ty::Tuple(fs) => Fields::wildcards_from_tys(pcx.cx, fs.iter()), + ty::Ref(_, rty, _) => Fields::wildcards_from_tys(pcx.cx, once(*rty)), ty::Adt(adt, args) => { if adt.is_box() { // The only legal patterns of type `Box` (outside `std`) are `_` and box // patterns. If we're here we can assume this is a box pattern. - Fields::wildcards_from_tys(pcx.cx, once(args.type_at(0)), pcx.span) + Fields::wildcards_from_tys(pcx.cx, once(args.type_at(0))) } else { let variant = &adt.variant(constructor.variant_index_for_adt(*adt)); let tys = Fields::list_variant_nonhidden_fields(pcx.cx, pcx.ty, variant) .map(|(_, ty)| ty); - Fields::wildcards_from_tys(pcx.cx, tys, pcx.span) + Fields::wildcards_from_tys(pcx.cx, tys) } } _ => bug!("Unexpected type for `Single` constructor: {:?}", pcx), @@ -1306,7 +1305,7 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { Slice(slice) => match *pcx.ty.kind() { ty::Slice(ty) | ty::Array(ty, _) => { let arity = slice.arity(); - Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty), pcx.span) + Fields::wildcards_from_tys(pcx.cx, (0..arity).map(|_| ty)) } _ => bug!("bad slice pattern {:?} {:?}", constructor, pcx), }, @@ -1625,7 +1624,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { let wildcard: &_ = pcx .cx .pattern_arena - .alloc(DeconstructedPat::wildcard(inner_ty, pcx.span)); + .alloc(DeconstructedPat::wildcard(inner_ty, DUMMY_SP)); let extra_wildcards = other_slice.arity() - self_slice.arity(); let extra_wildcards = (0..extra_wildcards).map(|_| wildcard); prefix.iter().chain(extra_wildcards).chain(suffix).collect() diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 29d1a58cb689..484b8e5776ca 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -521,8 +521,12 @@ pub(crate) struct MatchCheckCtxt<'p, 'tcx> { pub(crate) module: DefId, pub(crate) param_env: ty::ParamEnv<'tcx>, pub(crate) pattern_arena: &'p TypedArena>, + /// Lint level at the match. + pub(crate) match_lint_level: HirId, /// The span of the whole match, if applicable. pub(crate) match_span: Option, + /// Span of the scrutinee. + pub(crate) scrut_span: Span, /// Only produce `NON_EXHAUSTIVE_OMITTED_PATTERNS` lint on refutable patterns. pub(crate) refutable: bool, } @@ -552,8 +556,6 @@ pub(super) struct PatCtxt<'a, 'p, 'tcx> { pub(super) cx: &'a MatchCheckCtxt<'p, 'tcx>, /// Type of the current column under investigation. pub(super) ty: Ty<'tcx>, - /// Span of the current pattern under investigation. - pub(super) span: Span, /// Whether the current pattern is the whole pattern as found in a match arm, or if it's a /// subpattern. pub(super) is_top_level: bool, @@ -1020,7 +1022,7 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>( }; debug!("ty: {ty:?}"); - let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level }; + let pcx = &PatCtxt { cx, ty, is_top_level }; // Analyze the constructors present in this column. let ctors = matrix.heads().map(|p| p.ctor()); @@ -1169,7 +1171,7 @@ fn collect_nonexhaustive_missing_variants<'p, 'tcx>( let Some(ty) = column.head_ty() else { return Vec::new(); }; - let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level: false }; + let pcx = &PatCtxt { cx, ty, is_top_level: false }; let set = column.analyze_ctors(pcx); if set.present.is_empty() { @@ -1210,16 +1212,15 @@ fn collect_nonexhaustive_missing_variants<'p, 'tcx>( } /// Traverse the patterns to warn the user about ranges that overlap on their endpoints. -#[instrument(level = "debug", skip(cx, lint_root))] +#[instrument(level = "debug", skip(cx))] fn lint_overlapping_range_endpoints<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, column: &PatternColumn<'p, 'tcx>, - lint_root: HirId, ) { let Some(ty) = column.head_ty() else { return; }; - let pcx = &PatCtxt { cx, ty, span: DUMMY_SP, is_top_level: false }; + let pcx = &PatCtxt { cx, ty, is_top_level: false }; let set = column.analyze_ctors(pcx); @@ -1233,7 +1234,7 @@ fn lint_overlapping_range_endpoints<'p, 'tcx>( .collect(); cx.tcx.emit_spanned_lint( lint::builtin::OVERLAPPING_RANGE_ENDPOINTS, - lint_root, + cx.match_lint_level, this_span, OverlappingRangeEndpoints { overlap: overlaps, range: this_span }, ); @@ -1278,7 +1279,7 @@ fn lint_overlapping_range_endpoints<'p, 'tcx>( // Recurse into the fields. for ctor in set.present { for col in column.specialize(pcx, &ctor) { - lint_overlapping_range_endpoints(cx, &col, lint_root); + lint_overlapping_range_endpoints(cx, &col); } } } @@ -1319,9 +1320,7 @@ pub(crate) struct UsefulnessReport<'p, 'tcx> { pub(crate) fn compute_match_usefulness<'p, 'tcx>( cx: &MatchCheckCtxt<'p, 'tcx>, arms: &[MatchArm<'p, 'tcx>], - lint_root: HirId, scrut_ty: Ty<'tcx>, - scrut_span: Span, ) -> UsefulnessReport<'p, 'tcx> { let mut matrix = Matrix::new(cx, arms.iter(), scrut_ty); let non_exhaustiveness_witnesses = @@ -1345,13 +1344,13 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( let pat_column = PatternColumn::new(matrix.heads().collect()); // Lint on ranges that overlap on their endpoints, which is likely a mistake. - lint_overlapping_range_endpoints(cx, &pat_column, lint_root); + lint_overlapping_range_endpoints(cx, &pat_column); // Run the non_exhaustive_omitted_patterns lint. Only run on refutable patterns to avoid hitting // `if let`s. Only run if the match is exhaustive otherwise the error is redundant. if cx.refutable && report.non_exhaustiveness_witnesses.is_empty() { if !matches!( - cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, lint_root).0, + cx.tcx.lint_level_at_node(NON_EXHAUSTIVE_OMITTED_PATTERNS, cx.match_lint_level).0, rustc_session::lint::Level::Allow ) { let witnesses = collect_nonexhaustive_missing_variants(cx, &pat_column); @@ -1362,11 +1361,11 @@ pub(crate) fn compute_match_usefulness<'p, 'tcx>( // NB: The partner lint for structs lives in `compiler/rustc_hir_analysis/src/check/pat.rs`. cx.tcx.emit_spanned_lint( NON_EXHAUSTIVE_OMITTED_PATTERNS, - lint_root, - scrut_span, + cx.match_lint_level, + cx.scrut_span, NonExhaustiveOmittedPattern { scrut_ty, - uncovered: Uncovered::new(scrut_span, cx, witnesses), + uncovered: Uncovered::new(cx.scrut_span, cx, witnesses), }, ); } From 41e8f58fdc7c676681a09aebc71595a23de3d5b3 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 5 Nov 2023 15:00:46 +0100 Subject: [PATCH 25/93] Clarify the `Wildcard`/`Missing` situation --- .../src/thir/pattern/deconstruct_pat.rs | 16 ++-- .../src/thir/pattern/usefulness.rs | 86 +++++++++++-------- 2 files changed, 59 insertions(+), 43 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs index a4c1d20f454c..8ddc6c924e2a 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -72,13 +72,7 @@ //! The only place where we care about which constructors `Missing` represents is in diagnostics //! (see `super::usefulness::WitnessMatrix::apply_constructor`). //! -//! Extra special implementation detail: in fact, in the case where all the constructors are -//! missing, we replace `Missing` with `Wildcard` to signal this. It only makes a difference for -//! diagnostics: for `Missing` we list the missing constructors; for `Wildcard` we only output `_`. -//! -//! FIXME(Nadrieril): maybe `Missing { report_all: bool }` would be less confusing. -//! -//! We choose whether to specialize with `Missing`/`Wildcard` in +//! We choose whether to specialize with `Missing` in //! `super::usefulness::compute_exhaustiveness_and_reachability`. //! //! @@ -809,10 +803,16 @@ impl<'tcx> Constructor<'tcx> { #[inline] pub(super) fn is_covered_by<'p>(&self, pcx: &PatCtxt<'_, 'p, 'tcx>, other: &Self) -> bool { match (self, other) { + (Wildcard, _) => { + span_bug!( + pcx.cx.scrut_span, + "Constructor splitting should not have returned `Wildcard`" + ) + } // Wildcards cover anything (_, Wildcard) => true, // Only a wildcard pattern can match these special constructors. - (Wildcard | Missing { .. } | NonExhaustive | Hidden, _) => false, + (Missing { .. } | NonExhaustive | Hidden, _) => false, (Single, Single) => true, (Variant(self_id), Variant(other_id)) => self_id == other_id, diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 484b8e5776ca..65d762d8b5f2 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -928,7 +928,7 @@ impl<'tcx> WitnessMatrix<'tcx> { } /// Reverses specialization by the `Missing` constructor by pushing a whole new pattern. - fn push_pattern(&mut self, pat: &WitnessPat<'tcx>) { + fn push_pattern(&mut self, pat: WitnessPat<'tcx>) { for witness in self.0.iter_mut() { witness.push_pattern(pat.clone()) } @@ -940,37 +940,39 @@ impl<'tcx> WitnessMatrix<'tcx> { pcx: &PatCtxt<'_, '_, 'tcx>, missing_ctors: &[Constructor<'tcx>], ctor: &Constructor<'tcx>, + report_individual_missing_ctors: bool, ) { if self.is_empty() { return; } - if matches!(ctor, Constructor::Wildcard) { - let pat = WitnessPat::wild_from_ctor(pcx, Constructor::Wildcard); - self.push_pattern(&pat); - } else if matches!(ctor, Constructor::Missing) { - // We got the special `Missing` constructor, so each of the missing constructors gives a - // new pattern that is not caught by the match. We list those patterns and push them - // onto our current witnesses. - if missing_ctors.iter().any(|c| c.is_non_exhaustive()) { - // We only report `_` here; listing other constructors would be redundant. + if matches!(ctor, Constructor::Missing) { + // We got the special `Missing` constructor that stands for the constructors not present + // in the match. + if !report_individual_missing_ctors { + // Report `_` as missing. + let pat = WitnessPat::wild_from_ctor(pcx, Constructor::Wildcard); + self.push_pattern(pat); + } else if missing_ctors.iter().any(|c| c.is_non_exhaustive()) { + // We need to report a `_` anyway, so listing other constructors would be redundant. + // `NonExhaustive` is displayed as `_` just like `Wildcard`, but it will be picked + // up by diagnostics to add a note about why `_` is required here. let pat = WitnessPat::wild_from_ctor(pcx, Constructor::NonExhaustive); - self.push_pattern(&pat); + self.push_pattern(pat); } else { - let old_witnesses = std::mem::replace(self, Self::empty()); + // For each missing constructor `c`, we add a `c(_, _, _)` witness appropriately + // filled with wildcards. + let mut ret = Self::empty(); for ctor in missing_ctors { let pat = WitnessPat::wild_from_ctor(pcx, ctor.clone()); - let mut witnesses_with_missing_ctor = old_witnesses.clone(); - witnesses_with_missing_ctor.push_pattern(&pat); - self.extend(witnesses_with_missing_ctor) + // Clone `self` and add `c(_, _, _)` to each of its witnesses. + let mut wit_matrix = self.clone(); + wit_matrix.push_pattern(pat); + ret.extend(wit_matrix); } + *self = ret; } - } else if !missing_ctors.is_empty() { - // `ctor` isn't `Wildcard` or `Missing` and some ctors are missing, so we know - // `split_ctors` will contain `Wildcard` or `Missing`. - // For diagnostic purposes we choose to discard witnesses we got under `ctor`, which - // will let only the `Wildcard` or `Missing` be reported. - self.0.clear(); } else { + // Any other constructor we unspecialize as expected. for witness in self.0.iter_mut() { witness.apply_constructor(pcx, ctor) } @@ -1027,19 +1029,23 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>( // Analyze the constructors present in this column. let ctors = matrix.heads().map(|p| p.ctor()); let split_set = ConstructorSet::for_ty(pcx.cx, pcx.ty).split(pcx, ctors); + + let all_missing = split_set.present.is_empty(); + let always_report_all = is_top_level && !IntRange::is_integral(pcx.ty); + // Whether we should report "Enum::A and Enum::C are missing" or "_ is missing". + let report_individual_missing_ctors = always_report_all || !all_missing; + let mut split_ctors = split_set.present; - // We want to iterate over a full set of constructors, so if any is missing we add a wildcard. + let mut only_report_missing = false; if !split_set.missing.is_empty() { - let all_missing = split_ctors.is_empty(); - let always_report_missing = is_top_level && !IntRange::is_integral(pcx.ty); - let ctor = if all_missing && !always_report_missing { - Constructor::Wildcard - } else { - // Like `Wildcard`, except if it doesn't match a row this will report all the missing - // constructors instead of just `_`. - Constructor::Missing - }; - split_ctors.push(ctor); + // We need to iterate over a full set of constructors, so we add `Missing` to represent the + // missing ones. This is explained under "Constructor Splitting" at the top of this file. + split_ctors.push(Constructor::Missing); + // For diagnostic purposes we choose to only report the constructors that are missing. Since + // `Missing` matches only the wildcard rows, it matches fewer rows than any normal + // constructor and is therefore guaranteed to result in more witnesses. So skipping the + // other constructors does not jeopardize correctness. + only_report_missing = true; } let mut ret = WitnessMatrix::empty(); @@ -1050,9 +1056,18 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>( let mut witnesses = ensure_sufficient_stack(|| { compute_exhaustiveness_and_reachability(cx, &mut spec_matrix, false) }); - // Transform witnesses for `spec_matrix` into witnesses for `matrix`. - witnesses.apply_constructor(pcx, &split_set.missing, &ctor); - ret.extend(witnesses); + + if !only_report_missing || matches!(ctor, Constructor::Missing) { + // Transform witnesses for `spec_matrix` into witnesses for `matrix`. + witnesses.apply_constructor( + pcx, + &split_set.missing, + &ctor, + report_individual_missing_ctors, + ); + // Accumulate the found witnesses. + ret.extend(witnesses); + } // A parent row is useful if any of its children is. for child_row in spec_matrix.rows() { @@ -1067,6 +1082,7 @@ fn compute_exhaustiveness_and_reachability<'p, 'tcx>( row.head().set_reachable(); } } + ret } From 273cbb73047436927a680da5d1636d87be9aafe3 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Sun, 19 Nov 2023 23:56:27 +0100 Subject: [PATCH 26/93] Separate `PatStack` and `MatrixRow` This disentangles the row-specific tracking of `parent_row` etc from the logical operation of specialization. This means `wildcard_row` doesn't need to provide dummy values for `parent_row` etc anymore. --- .../src/thir/pattern/usefulness.rs | 148 ++++++++++++------ 1 file changed, 98 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 65d762d8b5f2..8f017833531c 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -567,39 +567,16 @@ impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> { } } -/// A row of the matrix. Represents a pattern-tuple under investigation. +/// Represents a pattern-tuple under investigation. #[derive(Clone)] struct PatStack<'p, 'tcx> { // Rows of len 1 are very common, which is why `SmallVec[_; 2]` works well. pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, - /// Whether the original arm had a guard. - is_under_guard: bool, - /// When we specialize, we remember which row of the original matrix produced a given row of the - /// specialized matrix. When we unspecialize, we use this to propagate reachability back up the - /// callstack. - /// At the start of the algorithm, this is the id of the arm this comes from (but we don't use - /// this fact anywhere). - parent_row: usize, - /// False when the matrix is just built. This is set to `true` by - /// [`compute_exhaustiveness_and_reachability`] if the arm is found to be reachable. - reachable: bool, } impl<'p, 'tcx> PatStack<'p, 'tcx> { - fn from_pattern( - pat: &'p DeconstructedPat<'p, 'tcx>, - parent_row: usize, - is_under_guard: bool, - ) -> Self { - PatStack { pats: smallvec![pat], parent_row, is_under_guard, reachable: false } - } - - fn from_vec( - pats: SmallVec<[&'p DeconstructedPat<'p, 'tcx>; 2]>, - parent_row: usize, - is_under_guard: bool, - ) -> Self { - PatStack { pats, parent_row, is_under_guard, reachable: false } + fn from_pattern(pat: &'p DeconstructedPat<'p, 'tcx>) -> Self { + PatStack { pats: smallvec![pat] } } fn is_empty(&self) -> bool { @@ -622,10 +599,80 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { // an or-pattern. Panics if `self` is empty. fn expand_or_pat<'a>(&'a self) -> impl Iterator> + Captures<'a> { self.head().flatten_or_pat().into_iter().map(move |pat| { - let mut new_patstack = - PatStack::from_pattern(pat, self.parent_row, self.is_under_guard); - new_patstack.pats.extend_from_slice(&self.pats[1..]); - new_patstack + let mut new_pats = smallvec![pat]; + new_pats.extend_from_slice(&self.pats[1..]); + PatStack { pats: new_pats } + }) + } + + /// This computes `specialize(ctor, self)`. See top of the file for explanations. + /// Only call if `ctor.is_covered_by(self.head().ctor())` is true. + fn pop_head_constructor( + &self, + pcx: &PatCtxt<'_, 'p, 'tcx>, + ctor: &Constructor<'tcx>, + ) -> PatStack<'p, 'tcx> { + // We pop the head pattern and push the new fields extracted from the arguments of + // `self.head()`. + let mut new_pats = self.head().specialize(pcx, ctor); + new_pats.extend_from_slice(&self.pats[1..]); + PatStack { pats: new_pats } + } +} + +impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + // We pretty-print similarly to the `Debug` impl of `Matrix`. + write!(f, "+")?; + for pat in self.iter() { + write!(f, " {pat:?} +")?; + } + Ok(()) + } +} + +/// A row of the matrix. +#[derive(Clone)] +struct MatrixRow<'p, 'tcx> { + // The patterns in the row. + pats: PatStack<'p, 'tcx>, + /// Whether the original arm had a guard. This is inherited when specializing. + is_under_guard: bool, + /// When we specialize, we remember which row of the original matrix produced a given row of the + /// specialized matrix. When we unspecialize, we use this to propagate reachability back up the + /// callstack. + parent_row: usize, + /// False when the matrix is just built. This is set to `true` by + /// [`compute_exhaustiveness_and_reachability`] if the arm is found to be reachable. + /// This is reset to `false` when specializing. + reachable: bool, +} + +impl<'p, 'tcx> MatrixRow<'p, 'tcx> { + fn is_empty(&self) -> bool { + self.pats.is_empty() + } + + fn len(&self) -> usize { + self.pats.len() + } + + fn head(&self) -> &'p DeconstructedPat<'p, 'tcx> { + self.pats.head() + } + + fn iter(&self) -> impl Iterator> { + self.pats.iter() + } + + // Recursively expand the first or-pattern into its subpatterns. Only useful if the pattern is + // an or-pattern. Panics if `self` is empty. + fn expand_or_pat<'a>(&'a self) -> impl Iterator> + Captures<'a> { + self.pats.expand_or_pat().map(|patstack| MatrixRow { + pats: patstack, + parent_row: self.parent_row, + is_under_guard: self.is_under_guard, + reachable: false, }) } @@ -636,23 +683,19 @@ impl<'p, 'tcx> PatStack<'p, 'tcx> { pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>, parent_row: usize, - ) -> PatStack<'p, 'tcx> { - // We pop the head pattern and push the new fields extracted from the arguments of - // `self.head()`. - let mut new_fields: SmallVec<[_; 2]> = self.head().specialize(pcx, ctor); - new_fields.extend_from_slice(&self.pats[1..]); - PatStack::from_vec(new_fields, parent_row, self.is_under_guard) + ) -> MatrixRow<'p, 'tcx> { + MatrixRow { + pats: self.pats.pop_head_constructor(pcx, ctor), + parent_row, + is_under_guard: self.is_under_guard, + reachable: false, + } } } -/// Pretty-printing for a matrix row. -impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { +impl<'p, 'tcx> fmt::Debug for MatrixRow<'p, 'tcx> { fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - write!(f, "+")?; - for pat in self.iter() { - write!(f, " {pat:?} +")?; - } - Ok(()) + self.pats.fmt(f) } } @@ -668,7 +711,7 @@ impl<'p, 'tcx> fmt::Debug for PatStack<'p, 'tcx> { /// the matrix will correspond to `scrutinee.0.Some.0` and the second column to `scrutinee.1`. #[derive(Clone)] struct Matrix<'p, 'tcx> { - rows: Vec>, + rows: Vec>, /// Stores an extra fictitious row full of wildcards. Mostly used to keep track of the type of /// each column. This must obey the same invariants as the real rows. wildcard_row: PatStack<'p, 'tcx>, @@ -677,7 +720,7 @@ struct Matrix<'p, 'tcx> { impl<'p, 'tcx> Matrix<'p, 'tcx> { /// Pushes a new row to the matrix. If the row starts with an or-pattern, this recursively /// expands it. Internal method, prefer [`Matrix::new`]. - fn expand_and_push(&mut self, row: PatStack<'p, 'tcx>) { + fn expand_and_push(&mut self, row: MatrixRow<'p, 'tcx>) { if !row.is_empty() && row.head().is_or_pat() { // Expand nested or-patterns. for new_row in row.expand_or_pat() { @@ -698,10 +741,15 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { 'p: 'a, { let wild_pattern = cx.pattern_arena.alloc(DeconstructedPat::wildcard(scrut_ty, DUMMY_SP)); - let wildcard_row = PatStack::from_pattern(wild_pattern, usize::MAX, false); + let wildcard_row = PatStack::from_pattern(wild_pattern); let mut matrix = Matrix { rows: vec![], wildcard_row }; for (row_id, arm) in iter.enumerate() { - let v = PatStack::from_pattern(arm.pat, row_id, arm.has_guard); + let v = MatrixRow { + pats: PatStack::from_pattern(arm.pat), + parent_row: row_id, // dummy, we won't read it + is_under_guard: arm.has_guard, + reachable: false, + }; matrix.expand_and_push(v); } matrix @@ -733,13 +781,13 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { fn rows<'a>( &'a self, - ) -> impl Iterator> + Clone + DoubleEndedIterator + ExactSizeIterator + ) -> impl Iterator> + Clone + DoubleEndedIterator + ExactSizeIterator { self.rows.iter() } fn rows_mut<'a>( &'a mut self, - ) -> impl Iterator> + DoubleEndedIterator + ExactSizeIterator + ) -> impl Iterator> + DoubleEndedIterator + ExactSizeIterator { self.rows.iter_mut() } @@ -757,7 +805,7 @@ impl<'p, 'tcx> Matrix<'p, 'tcx> { pcx: &PatCtxt<'_, 'p, 'tcx>, ctor: &Constructor<'tcx>, ) -> Matrix<'p, 'tcx> { - let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor, usize::MAX); + let wildcard_row = self.wildcard_row.pop_head_constructor(pcx, ctor); let mut matrix = Matrix { rows: vec![], wildcard_row }; for (i, row) in self.rows().enumerate() { if ctor.is_covered_by(pcx, row.head().ctor()) { From ebfb95a357122f8a1095d5078a6712dfa66a24f8 Mon Sep 17 00:00:00 2001 From: Ralf Jung Date: Wed, 22 Nov 2023 07:23:40 +0100 Subject: [PATCH 27/93] add a test --- tests/ui/abi/arm-unadjusted-intrinsic.rs | 54 ++++++++++++++++++++++++ 1 file changed, 54 insertions(+) create mode 100644 tests/ui/abi/arm-unadjusted-intrinsic.rs diff --git a/tests/ui/abi/arm-unadjusted-intrinsic.rs b/tests/ui/abi/arm-unadjusted-intrinsic.rs new file mode 100644 index 000000000000..33ea79275263 --- /dev/null +++ b/tests/ui/abi/arm-unadjusted-intrinsic.rs @@ -0,0 +1,54 @@ +// build-pass +// revisions: arm +//[arm] compile-flags: --target arm-unknown-linux-gnueabi +//[arm] needs-llvm-components: arm +// revisions: aarch64 +//[aarch64] compile-flags: --target aarch64-unknown-linux-gnu +//[aarch64] needs-llvm-components: aarch64 +#![feature( + no_core, lang_items, link_llvm_intrinsics, + abi_unadjusted, repr_simd, arm_target_feature, +)] +#![no_std] +#![no_core] +#![crate_type = "lib"] +#![allow(non_camel_case_types)] + +/// To work cross-target this test must be no_core. +/// This little prelude supplies what we need. +#[lang = "sized"] +pub trait Sized {} + +#[lang = "copy"] +pub trait Copy: Sized {} +impl Copy for i8 {} +impl Copy for *const T {} +impl Copy for *mut T {} + + +// Regression test for https://github.com/rust-lang/rust/issues/118124. + +#[repr(simd)] +pub struct int8x16_t( + pub(crate) i8, pub(crate) i8, pub(crate) i8, pub(crate) i8, + pub(crate) i8, pub(crate) i8, pub(crate) i8, pub(crate) i8, + pub(crate) i8, pub(crate) i8, pub(crate) i8, pub(crate) i8, + pub(crate) i8, pub(crate) i8, pub(crate) i8, pub(crate) i8, +); +impl Copy for int8x16_t {} + +#[repr(C)] +pub struct int8x16x4_t(pub int8x16_t, pub int8x16_t, pub int8x16_t, pub int8x16_t); +impl Copy for int8x16x4_t {} + +#[target_feature(enable = "neon")] +#[cfg_attr(target_arch = "arm", target_feature(enable = "v7"))] +pub unsafe fn vld1q_s8_x4(a: *const i8) -> int8x16x4_t { + #[allow(improper_ctypes)] + extern "unadjusted" { + #[cfg_attr(target_arch = "arm", link_name = "llvm.arm.neon.vld1x4.v16i8.p0i8")] + #[cfg_attr(target_arch = "aarch64", link_name = "llvm.aarch64.neon.ld1x4.v16i8.p0i8")] + fn vld1q_s8_x4_(a: *const i8) -> int8x16x4_t; + } + vld1q_s8_x4_(a) +} From 45bad64ab43bd5af4ef6d540294c81e6bb4f89be Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 17 Nov 2023 15:21:00 -0500 Subject: [PATCH 28/93] rustc_lint: remove superfluous assertion `Option::unwrap` is called on the next line. --- compiler/rustc_lint/src/late.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 551fe23f9f19..b47b3d41b12b 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -33,7 +33,6 @@ use std::cell::Cell; /// Extract the `LintStore` from the query context. /// This function exists because we've erased `LintStore` as `dyn Any` in the session. pub fn unerased_lint_store(sess: &Session) -> &LintStore { - assert!(sess.lint_store.is_some()); let store: &Lrc<_> = sess.lint_store.as_ref().unwrap(); let store: &dyn Any = &**store; store.downcast_ref().unwrap() From 55393b6eca0c203b03b76447e42af0bd1d06204d Mon Sep 17 00:00:00 2001 From: Tamir Duberstein Date: Fri, 17 Nov 2023 15:24:55 -0500 Subject: [PATCH 29/93] rustc_session: implement latent TODO --- compiler/rustc_lint/src/context.rs | 4 +++- compiler/rustc_lint/src/late.rs | 5 +++-- compiler/rustc_lint/src/lib.rs | 1 + compiler/rustc_session/src/session.rs | 7 +++---- 4 files changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index fbcb49b1df5c..9bc9f88d3f72 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -36,7 +36,7 @@ use rustc_middle::ty::{self, print::Printer, GenericArg, RegisteredTools, Ty, Ty use rustc_session::config::ExpectedValues; use rustc_session::lint::{BuiltinLintDiagnostics, LintExpectationId}; use rustc_session::lint::{FutureIncompatibleInfo, Level, Lint, LintBuffer, LintId}; -use rustc_session::Session; +use rustc_session::{LintStoreMarker, Session}; use rustc_span::edit_distance::find_best_match_for_name; use rustc_span::symbol::{sym, Ident, Symbol}; use rustc_span::{BytePos, Span}; @@ -77,6 +77,8 @@ pub struct LintStore { lint_groups: FxHashMap<&'static str, LintGroup>, } +impl LintStoreMarker for LintStore {} + /// The target of the `by_name` map, which accounts for renaming/deprecation. #[derive(Debug)] enum TargetLint { diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index b47b3d41b12b..4f0cf5c52542 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -30,8 +30,9 @@ use rustc_span::Span; use std::any::Any; use std::cell::Cell; -/// Extract the `LintStore` from the query context. -/// This function exists because we've erased `LintStore` as `dyn Any` in the session. +/// Extract the [`LintStore`] from [`Session`]. +/// +/// This function exists because [`Session::lint_store`] is type-erased. pub fn unerased_lint_store(sess: &Session) -> &LintStore { let store: &Lrc<_> = sess.lint_store.as_ref().unwrap(); let store: &dyn Any = &**store; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a48a8bd71b9a..6585d4a6281f 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -39,6 +39,7 @@ #![feature(min_specialization)] #![feature(never_type)] #![feature(rustc_attrs)] +#![cfg_attr(bootstrap, feature(trait_upcasting))] #![recursion_limit = "256"] #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index efd75ce61518..20a67d6d036c 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -139,6 +139,8 @@ pub struct CompilerIO { pub temps_dir: Option, } +pub trait LintStoreMarker: Any + DynSync + DynSend {} + /// Represents the data associated with a compilation /// session for a single crate. pub struct Session { @@ -171,10 +173,7 @@ pub struct Session { pub jobserver: Client, /// This only ever stores a `LintStore` but we don't want a dependency on that type here. - /// - /// FIXME(Centril): consider `dyn LintStoreMarker` once - /// we can upcast to `Any` for some additional type safety. - pub lint_store: Option>, + pub lint_store: Option>, /// Should be set if any lints are registered in `lint_store`. pub registered_lints: bool, From fbaa24ee35dffb044e4895ad68f01c3f06046275 Mon Sep 17 00:00:00 2001 From: Ben Kimock Date: Fri, 27 Oct 2023 21:26:43 -0400 Subject: [PATCH 30/93] Call FileEncoder::finish in rmeta encoding --- Cargo.lock | 1 + compiler/rustc_codegen_ssa/src/lib.rs | 2 +- .../src/persist/file_format.rs | 4 +- .../rustc_incremental/src/persist/save.rs | 3 -- compiler/rustc_interface/Cargo.toml | 1 + compiler/rustc_interface/src/queries.rs | 10 ++++- compiler/rustc_metadata/messages.ftl | 5 +-- compiler/rustc_metadata/src/errors.rs | 9 +--- compiler/rustc_metadata/src/rmeta/encoder.rs | 34 +++++++++------ .../rustc_middle/src/query/on_disk_cache.rs | 3 +- compiler/rustc_middle/src/ty/context.rs | 4 ++ .../rustc_query_system/src/dep_graph/graph.rs | 2 +- compiler/rustc_serialize/src/opaque.rs | 43 ++++++++++++++++--- src/librustdoc/scrape_examples.rs | 2 +- 14 files changed, 82 insertions(+), 41 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 8c9b12028f09..6dc1ea75d8e3 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -4041,6 +4041,7 @@ dependencies = [ "rustc_query_impl", "rustc_query_system", "rustc_resolve", + "rustc_serialize", "rustc_session", "rustc_span", "rustc_symbol_mangling", diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 8a82a37df9cc..5514a32b23a7 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -226,7 +226,7 @@ impl CodegenResults { encoder.emit_raw_bytes(&RLINK_VERSION.to_be_bytes()); encoder.emit_str(sess.cfg_version); Encodable::encode(codegen_results, &mut encoder); - encoder.finish() + encoder.finish().map_err(|(_path, err)| err) } pub fn deserialize_rlink(sess: &Session, data: Vec) -> Result { diff --git a/compiler/rustc_incremental/src/persist/file_format.rs b/compiler/rustc_incremental/src/persist/file_format.rs index 25bf83f64a08..b5742b97d024 100644 --- a/compiler/rustc_incremental/src/persist/file_format.rs +++ b/compiler/rustc_incremental/src/persist/file_format.rs @@ -80,8 +80,8 @@ where ); debug!("save: data written to disk successfully"); } - Err(err) => { - sess.emit_err(errors::WriteNew { name, path: path_buf, err }); + Err((path, err)) => { + sess.emit_err(errors::WriteNew { name, path, err }); } } } diff --git a/compiler/rustc_incremental/src/persist/save.rs b/compiler/rustc_incremental/src/persist/save.rs index fa21320be263..d6320d680e77 100644 --- a/compiler/rustc_incremental/src/persist/save.rs +++ b/compiler/rustc_incremental/src/persist/save.rs @@ -50,9 +50,6 @@ pub fn save_dep_graph(tcx: TyCtxt<'_>) { join( move || { sess.time("incr_comp_persist_dep_graph", || { - if let Err(err) = tcx.dep_graph.encode(&tcx.sess.prof) { - sess.emit_err(errors::WriteDepGraph { path: &staging_dep_graph_path, err }); - } if let Err(err) = fs::rename(&staging_dep_graph_path, &dep_graph_path) { sess.emit_err(errors::MoveDepGraph { from: &staging_dep_graph_path, diff --git a/compiler/rustc_interface/Cargo.toml b/compiler/rustc_interface/Cargo.toml index fd587e53f915..319e81758094 100644 --- a/compiler/rustc_interface/Cargo.toml +++ b/compiler/rustc_interface/Cargo.toml @@ -40,6 +40,7 @@ rustc_privacy = { path = "../rustc_privacy" } rustc_query_impl = { path = "../rustc_query_impl" } rustc_query_system = { path = "../rustc_query_system" } rustc_resolve = { path = "../rustc_resolve" } +rustc_serialize = { path = "../rustc_serialize" } rustc_session = { path = "../rustc_session" } rustc_span = { path = "../rustc_span" } rustc_symbol_mangling = { path = "../rustc_symbol_mangling" } diff --git a/compiler/rustc_interface/src/queries.rs b/compiler/rustc_interface/src/queries.rs index 1c65cf19cde3..bee27dc2d69c 100644 --- a/compiler/rustc_interface/src/queries.rs +++ b/compiler/rustc_interface/src/queries.rs @@ -1,6 +1,6 @@ use crate::errors::{FailedWritingFile, RustcErrorFatal, RustcErrorUnexpectedAnnotation}; use crate::interface::{Compiler, Result}; -use crate::{passes, util}; +use crate::{errors, passes, util}; use rustc_ast as ast; use rustc_codegen_ssa::traits::CodegenBackend; @@ -15,6 +15,7 @@ use rustc_metadata::creader::CStore; use rustc_middle::arena::Arena; use rustc_middle::dep_graph::DepGraph; use rustc_middle::ty::{GlobalCtxt, TyCtxt}; +use rustc_serialize::opaque::FileEncodeResult; use rustc_session::config::{self, CrateType, OutputFilenames, OutputType}; use rustc_session::cstore::Untracked; use rustc_session::output::find_crate_name; @@ -102,6 +103,10 @@ impl<'tcx> Queries<'tcx> { } } + pub fn finish(&self) -> FileEncodeResult { + if let Some(gcx) = self.gcx_cell.get() { gcx.finish() } else { Ok(0) } + } + pub fn parse(&self) -> Result> { self.parse.compute(|| { passes::parse(&self.compiler.sess).map_err(|mut parse_error| parse_error.emit()) @@ -317,6 +322,9 @@ impl Compiler { // The timer's lifetime spans the dropping of `queries`, which contains // the global context. _timer = Some(self.sess.timer("free_global_ctxt")); + if let Err((path, error)) = queries.finish() { + self.sess.emit_err(errors::FailedWritingFile { path: &path, error }); + } ret } diff --git a/compiler/rustc_metadata/messages.ftl b/compiler/rustc_metadata/messages.ftl index d1815717e220..44b235a6d3d2 100644 --- a/compiler/rustc_metadata/messages.ftl +++ b/compiler/rustc_metadata/messages.ftl @@ -63,11 +63,8 @@ metadata_extern_location_not_file = metadata_fail_create_file_encoder = failed to create file encoder: {$err} -metadata_fail_seek_file = - failed to seek the file: {$err} - metadata_fail_write_file = - failed to write to the file: {$err} + failed to write to `{$path}`: {$err} metadata_failed_copy_to_stdout = failed to copy {$filename} to stdout: {$err} diff --git a/compiler/rustc_metadata/src/errors.rs b/compiler/rustc_metadata/src/errors.rs index 70daee291e72..edc8d8532d3b 100644 --- a/compiler/rustc_metadata/src/errors.rs +++ b/compiler/rustc_metadata/src/errors.rs @@ -307,15 +307,10 @@ pub struct FailCreateFileEncoder { pub err: Error, } -#[derive(Diagnostic)] -#[diag(metadata_fail_seek_file)] -pub struct FailSeekFile { - pub err: Error, -} - #[derive(Diagnostic)] #[diag(metadata_fail_write_file)] -pub struct FailWriteFile { +pub struct FailWriteFile<'a> { + pub path: &'a Path, pub err: Error, } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 19add1ef1acf..44e53d07f005 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1,4 +1,4 @@ -use crate::errors::{FailCreateFileEncoder, FailSeekFile, FailWriteFile}; +use crate::errors::{FailCreateFileEncoder, FailWriteFile}; use crate::rmeta::def_path_hash_map::DefPathHashMapRef; use crate::rmeta::table::TableBuilder; use crate::rmeta::*; @@ -42,6 +42,7 @@ use rustc_span::symbol::{sym, Symbol}; use rustc_span::{self, ExternalSource, FileName, SourceFile, Span, SpanData, SyntaxContext}; use std::borrow::Borrow; use std::collections::hash_map::Entry; +use std::fs::File; use std::hash::Hash; use std::io::{Read, Seek, Write}; use std::num::NonZeroUsize; @@ -2250,25 +2251,34 @@ fn encode_metadata_impl(tcx: TyCtxt<'_>, path: &Path) { // culminating in the `CrateRoot` which points to all of it. let root = ecx.encode_crate_root(); - ecx.opaque.flush(); + // Make sure we report any errors from writing to the file. + // If we forget this, compilation can succeed with an incomplete rmeta file, + // causing an ICE when the rmeta file is read by another compilation. + if let Err((path, err)) = ecx.opaque.finish() { + tcx.sess.emit_err(FailWriteFile { path: &path, err }); + } - let mut file = ecx.opaque.file(); + let file = ecx.opaque.file(); + if let Err(err) = encode_root_position(file, root.position.get()) { + tcx.sess.emit_err(FailWriteFile { path: ecx.opaque.path(), err }); + } + + // Record metadata size for self-profiling + tcx.prof.artifact_size("crate_metadata", "crate_metadata", file.metadata().unwrap().len()); +} + +fn encode_root_position(mut file: &File, pos: usize) -> Result<(), std::io::Error> { // We will return to this position after writing the root position. let pos_before_seek = file.stream_position().unwrap(); // Encode the root position. let header = METADATA_HEADER.len(); - file.seek(std::io::SeekFrom::Start(header as u64)) - .unwrap_or_else(|err| tcx.sess.emit_fatal(FailSeekFile { err })); - let pos = root.position.get(); - file.write_all(&[(pos >> 24) as u8, (pos >> 16) as u8, (pos >> 8) as u8, (pos >> 0) as u8]) - .unwrap_or_else(|err| tcx.sess.emit_fatal(FailWriteFile { err })); + file.seek(std::io::SeekFrom::Start(header as u64))?; + file.write_all(&[(pos >> 24) as u8, (pos >> 16) as u8, (pos >> 8) as u8, (pos >> 0) as u8])?; // Return to the position where we are before writing the root position. - file.seek(std::io::SeekFrom::Start(pos_before_seek)).unwrap(); - - // Record metadata size for self-profiling - tcx.prof.artifact_size("crate_metadata", "crate_metadata", file.metadata().unwrap().len()); + file.seek(std::io::SeekFrom::Start(pos_before_seek))?; + Ok(()) } pub fn provide(providers: &mut Providers) { diff --git a/compiler/rustc_middle/src/query/on_disk_cache.rs b/compiler/rustc_middle/src/query/on_disk_cache.rs index ee6567f6cc42..f37cfe8b0a11 100644 --- a/compiler/rustc_middle/src/query/on_disk_cache.rs +++ b/compiler/rustc_middle/src/query/on_disk_cache.rs @@ -25,7 +25,6 @@ use rustc_span::source_map::{SourceMap, StableSourceFileId}; use rustc_span::{BytePos, ExpnData, ExpnHash, Pos, RelativeBytePos, SourceFile, Span}; use rustc_span::{CachingSourceMapView, Symbol}; use std::collections::hash_map::Entry; -use std::io; use std::mem; const TAG_FILE_FOOTER: u128 = 0xC0FFEE_C0FFEE_C0FFEE_C0FFEE_C0FFEE; @@ -862,7 +861,7 @@ impl<'a, 'tcx> CacheEncoder<'a, 'tcx> { } #[inline] - fn finish(self) -> Result { + fn finish(mut self) -> FileEncodeResult { self.encoder.finish() } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 62b0536dabee..82080205c8d3 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -597,6 +597,10 @@ impl<'tcx> GlobalCtxt<'tcx> { let icx = tls::ImplicitCtxt::new(self); tls::enter_context(&icx, || f(icx.tcx)) } + + pub fn finish(&self) -> FileEncodeResult { + self.dep_graph.finish_encoding(&self.sess.prof) + } } impl<'tcx> TyCtxt<'tcx> { diff --git a/compiler/rustc_query_system/src/dep_graph/graph.rs b/compiler/rustc_query_system/src/dep_graph/graph.rs index d720744a7a74..5acd012ef047 100644 --- a/compiler/rustc_query_system/src/dep_graph/graph.rs +++ b/compiler/rustc_query_system/src/dep_graph/graph.rs @@ -982,7 +982,7 @@ impl DepGraph { } } - pub fn encode(&self, profiler: &SelfProfilerRef) -> FileEncodeResult { + pub fn finish_encoding(&self, profiler: &SelfProfilerRef) -> FileEncodeResult { if let Some(data) = &self.data { data.current.encoder.steal().finish(profiler) } else { diff --git a/compiler/rustc_serialize/src/opaque.rs b/compiler/rustc_serialize/src/opaque.rs index 552554390515..cc8d1c25092e 100644 --- a/compiler/rustc_serialize/src/opaque.rs +++ b/compiler/rustc_serialize/src/opaque.rs @@ -5,12 +5,13 @@ use std::io::{self, Write}; use std::marker::PhantomData; use std::ops::Range; use std::path::Path; +use std::path::PathBuf; // ----------------------------------------------------------------------------- // Encoder // ----------------------------------------------------------------------------- -pub type FileEncodeResult = Result; +pub type FileEncodeResult = Result; /// The size of the buffer in `FileEncoder`. const BUF_SIZE: usize = 8192; @@ -34,6 +35,9 @@ pub struct FileEncoder { // This is used to implement delayed error handling, as described in the // comment on `trait Encoder`. res: Result<(), io::Error>, + path: PathBuf, + #[cfg(debug_assertions)] + finished: bool, } impl FileEncoder { @@ -41,14 +45,18 @@ impl FileEncoder { // File::create opens the file for writing only. When -Zmeta-stats is enabled, the metadata // encoder rewinds the file to inspect what was written. So we need to always open the file // for reading and writing. - let file = File::options().read(true).write(true).create(true).truncate(true).open(path)?; + let file = + File::options().read(true).write(true).create(true).truncate(true).open(&path)?; Ok(FileEncoder { buf: vec![0u8; BUF_SIZE].into_boxed_slice().try_into().unwrap(), + path: path.as_ref().into(), buffered: 0, flushed: 0, file, res: Ok(()), + #[cfg(debug_assertions)] + finished: false, }) } @@ -63,6 +71,10 @@ impl FileEncoder { #[cold] #[inline(never)] pub fn flush(&mut self) { + #[cfg(debug_assertions)] + { + self.finished = false; + } if self.res.is_ok() { self.res = self.file.write_all(&self.buf[..self.buffered]); } @@ -74,6 +86,10 @@ impl FileEncoder { &self.file } + pub fn path(&self) -> &Path { + &self.path + } + #[inline] fn buffer_empty(&mut self) -> &mut [u8] { // SAFETY: self.buffered is inbounds as an invariant of the type @@ -97,6 +113,10 @@ impl FileEncoder { #[inline] fn write_all(&mut self, buf: &[u8]) { + #[cfg(debug_assertions)] + { + self.finished = false; + } if let Some(dest) = self.buffer_empty().get_mut(..buf.len()) { dest.copy_from_slice(buf); self.buffered += buf.len(); @@ -121,6 +141,10 @@ impl FileEncoder { /// with one instruction, so while this does in some sense do wasted work, we come out ahead. #[inline] pub fn write_with(&mut self, visitor: impl FnOnce(&mut [u8; N]) -> usize) { + #[cfg(debug_assertions)] + { + self.finished = false; + } let flush_threshold = const { BUF_SIZE.checked_sub(N).unwrap() }; if std::intrinsics::unlikely(self.buffered > flush_threshold) { self.flush(); @@ -152,20 +176,25 @@ impl FileEncoder { }) } - pub fn finish(mut self) -> Result { + pub fn finish(&mut self) -> FileEncodeResult { self.flush(); + #[cfg(debug_assertions)] + { + self.finished = true; + } match std::mem::replace(&mut self.res, Ok(())) { Ok(()) => Ok(self.position()), - Err(e) => Err(e), + Err(e) => Err((self.path.clone(), e)), } } } +#[cfg(debug_assertions)] impl Drop for FileEncoder { fn drop(&mut self) { - // Likely to be a no-op, because `finish` should have been called and - // it also flushes. But do it just in case. - self.flush(); + if !std::thread::panicking() { + assert!(self.finished); + } } } diff --git a/src/librustdoc/scrape_examples.rs b/src/librustdoc/scrape_examples.rs index dd52deef6724..14680fdb064f 100644 --- a/src/librustdoc/scrape_examples.rs +++ b/src/librustdoc/scrape_examples.rs @@ -325,7 +325,7 @@ pub(crate) fn run( // Save output to provided path let mut encoder = FileEncoder::new(options.output_path).map_err(|e| e.to_string())?; calls.encode(&mut encoder); - encoder.finish().map_err(|e| e.to_string())?; + encoder.finish().map_err(|(_path, e)| e.to_string())?; Ok(()) }; From aff6c741d466610576b02fde72d139aa8c6ec0a8 Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 13 Nov 2023 14:43:53 +0300 Subject: [PATCH 31/93] remove unused pub fn --- compiler/rustc_codegen_llvm/src/llvm/ffi.rs | 7 --- compiler/rustc_codegen_llvm/src/type_.rs | 4 -- .../src/interpret/projection.rs | 4 +- compiler/rustc_graphviz/src/lib.rs | 27 --------- .../src/fn_ctxt/suggestions.rs | 1 + compiler/rustc_infer/src/infer/mod.rs | 13 +---- .../rustc_llvm/llvm-wrapper/PassWrapper.cpp | 26 --------- compiler/rustc_middle/src/mir/query.rs | 58 ------------------- compiler/rustc_middle/src/traits/query.rs | 11 ---- compiler/rustc_middle/src/ty/generic_args.rs | 7 --- compiler/rustc_middle/src/ty/mod.rs | 19 ------ compiler/rustc_middle/src/ty/util.rs | 16 ----- compiler/rustc_span/src/lib.rs | 7 --- 13 files changed, 4 insertions(+), 196 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs index 245baad26128..df4cd8ea0bd5 100644 --- a/compiler/rustc_codegen_llvm/src/llvm/ffi.rs +++ b/compiler/rustc_codegen_llvm/src/llvm/ffi.rs @@ -891,7 +891,6 @@ extern "C" { pub fn LLVMSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Node: &'a Value); pub fn LLVMGlobalSetMetadata<'a>(Val: &'a Value, KindID: c_uint, Metadata: &'a Metadata); pub fn LLVMValueAsMetadata(Node: &Value) -> &Metadata; - pub fn LLVMIsAFunction(Val: &Value) -> Option<&Value>; // Operations on constants of any type pub fn LLVMConstNull(Ty: &Type) -> &Value; @@ -955,7 +954,6 @@ extern "C" { pub fn LLVMConstPtrToInt<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMConstIntToPtr<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMConstBitCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; - pub fn LLVMConstPointerCast<'a>(ConstantVal: &'a Value, ToType: &'a Type) -> &'a Value; pub fn LLVMGetAggregateElement(ConstantVal: &Value, Idx: c_uint) -> Option<&Value>; // Operations on global variables, functions, and aliases (globals) @@ -2346,11 +2344,6 @@ extern "C" { len: usize, Identifier: *const c_char, ) -> Option<&Module>; - pub fn LLVMRustGetBitcodeSliceFromObjectData( - Data: *const u8, - len: usize, - out_len: &mut usize, - ) -> *const u8; pub fn LLVMRustGetSliceFromObjectDataByName( data: *const u8, len: usize, diff --git a/compiler/rustc_codegen_llvm/src/type_.rs b/compiler/rustc_codegen_llvm/src/type_.rs index 06b7703672fe..447c4ed1f0c6 100644 --- a/compiler/rustc_codegen_llvm/src/type_.rs +++ b/compiler/rustc_codegen_llvm/src/type_.rs @@ -227,10 +227,6 @@ impl<'ll, 'tcx> BaseTypeMethods<'tcx> for CodegenCx<'ll, 'tcx> { } impl Type { - pub fn i8_llcx(llcx: &llvm::Context) -> &Type { - unsafe { llvm::LLVMInt8TypeInContext(llcx) } - } - /// Creates an integer type with the given number of bits, e.g., i24 pub fn ix_llcx(llcx: &llvm::Context, num_bits: u64) -> &Type { unsafe { llvm::LLVMIntTypeInContext(llcx, num_bits as c_uint) } diff --git a/compiler/rustc_const_eval/src/interpret/projection.rs b/compiler/rustc_const_eval/src/interpret/projection.rs index 6694c43c9926..c8977aac0fc5 100644 --- a/compiler/rustc_const_eval/src/interpret/projection.rs +++ b/compiler/rustc_const_eval/src/interpret/projection.rs @@ -256,13 +256,13 @@ where } /// Iterates over all fields of an array. Much more efficient than doing the - /// same by repeatedly calling `operand_index`. + /// same by repeatedly calling `project_index`. pub fn project_array_fields<'a, P: Projectable<'tcx, M::Provenance>>( &self, base: &'a P, ) -> InterpResult<'tcx, ArrayIterator<'tcx, 'a, M::Provenance, P>> { let abi::FieldsShape::Array { stride, .. } = base.layout().fields else { - span_bug!(self.cur_span(), "operand_array_fields: expected an array layout"); + span_bug!(self.cur_span(), "project_array_fields: expected an array layout"); }; let len = base.len(self)?; let field_layout = base.layout().field(self, 0); diff --git a/compiler/rustc_graphviz/src/lib.rs b/compiler/rustc_graphviz/src/lib.rs index 9abd7aec98d1..eba3215d9315 100644 --- a/compiler/rustc_graphviz/src/lib.rs +++ b/compiler/rustc_graphviz/src/lib.rs @@ -522,33 +522,6 @@ impl<'a> LabelText<'a> { HtmlStr(ref s) => format!("<{s}>"), } } - - /// Decomposes content into string suitable for making EscStr that - /// yields same content as self. The result obeys the law - /// render(`lt`) == render(`EscStr(lt.pre_escaped_content())`) for - /// all `lt: LabelText`. - fn pre_escaped_content(self) -> Cow<'a, str> { - match self { - EscStr(s) => s, - LabelStr(s) => { - if s.contains('\\') { - s.escape_default().to_string().into() - } else { - s - } - } - HtmlStr(s) => s, - } - } - - /// Puts `suffix` on a line below this label, with a blank line separator. - pub fn suffix_line(self, suffix: LabelText<'_>) -> LabelText<'static> { - let mut prefix = self.pre_escaped_content().into_owned(); - let suffix = suffix.pre_escaped_content(); - prefix.push_str(r"\n\n"); - prefix.push_str(&suffix); - EscStr(prefix.into()) - } } pub type Nodes<'a, N> = Cow<'a, [N]>; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 78e755378f5f..0a15d69f474a 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -609,6 +609,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } let pin_did = self.tcx.lang_items().pin_type(); + // FIXME: replace mk_box with? // This guards the `unwrap` and `mk_box` below. if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() { return false; diff --git a/compiler/rustc_infer/src/infer/mod.rs b/compiler/rustc_infer/src/infer/mod.rs index d6c7a24476f9..24c5d7bbe213 100644 --- a/compiler/rustc_infer/src/infer/mod.rs +++ b/compiler/rustc_infer/src/infer/mod.rs @@ -32,7 +32,7 @@ use rustc_middle::ty::error::{ExpectedFound, TypeError}; use rustc_middle::ty::fold::BoundVarReplacerDelegate; use rustc_middle::ty::fold::{TypeFoldable, TypeFolder, TypeSuperFoldable}; use rustc_middle::ty::relate::RelateResult; -use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; +use rustc_middle::ty::visit::TypeVisitableExt; pub use rustc_middle::ty::IntVarValue; use rustc_middle::ty::{self, GenericParamDefKind, InferConst, InferTy, Ty, TyCtxt}; use rustc_middle::ty::{ConstVid, EffectVid, FloatVid, IntVid, TyVid}; @@ -1406,17 +1406,6 @@ impl<'tcx> InferCtxt<'tcx> { value.fold_with(&mut r) } - /// Returns the first unresolved type or const variable contained in `T`. - pub fn first_unresolved_const_or_ty_var( - &self, - value: &T, - ) -> Option<(ty::Term<'tcx>, Option)> - where - T: TypeVisitable>, - { - value.visit_with(&mut resolve::UnresolvedTypeOrConstFinder::new(self)).break_value() - } - pub fn probe_const_var(&self, vid: ty::ConstVid) -> Result, ty::UniverseIndex> { match self.inner.borrow_mut().const_unification_table().probe_value(vid).val { ConstVariableValue::Known { value } => Ok(value), diff --git a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp index b4c8fb1a2f1d..d2cd79b456a3 100644 --- a/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp +++ b/compiler/rustc_llvm/llvm-wrapper/PassWrapper.cpp @@ -1562,32 +1562,6 @@ LLVMRustParseBitcodeForLTO(LLVMContextRef Context, return wrap(std::move(*SrcOrError).release()); } -// Find the bitcode section in the object file data and return it as a slice. -// Fail if the bitcode section is present but empty. -// -// On success, the return value is the pointer to the start of the slice and -// `out_len` is filled with the (non-zero) length. On failure, the return value -// is `nullptr` and `out_len` is set to zero. -extern "C" const char* -LLVMRustGetBitcodeSliceFromObjectData(const char *data, - size_t len, - size_t *out_len) { - *out_len = 0; - - StringRef Data(data, len); - MemoryBufferRef Buffer(Data, ""); // The id is unused. - - Expected BitcodeOrError = - object::IRObjectFile::findBitcodeInMemBuffer(Buffer); - if (!BitcodeOrError) { - LLVMRustSetLastError(toString(BitcodeOrError.takeError()).c_str()); - return nullptr; - } - - *out_len = BitcodeOrError->getBufferSize(); - return BitcodeOrError->getBufferStart(); -} - // Find a section of an object file by name. Fail if the section is missing or // empty. extern "C" const char *LLVMRustGetSliceFromObjectDataByName(const char *data, diff --git a/compiler/rustc_middle/src/mir/query.rs b/compiler/rustc_middle/src/mir/query.rs index 4f98c302298e..ab8fef5129b5 100644 --- a/compiler/rustc_middle/src/mir/query.rs +++ b/compiler/rustc_middle/src/mir/query.rs @@ -42,64 +42,6 @@ pub enum UnsafetyViolationDetails { CallToFunctionWith, } -impl UnsafetyViolationDetails { - pub fn description_and_note(&self) -> (&'static str, &'static str) { - use UnsafetyViolationDetails::*; - match self { - CallToUnsafeFunction => ( - "call to unsafe function", - "consult the function's documentation for information on how to avoid undefined \ - behavior", - ), - UseOfInlineAssembly => ( - "use of inline assembly", - "inline assembly is entirely unchecked and can cause undefined behavior", - ), - InitializingTypeWith => ( - "initializing type with `rustc_layout_scalar_valid_range` attr", - "initializing a layout restricted type's field with a value outside the valid \ - range is undefined behavior", - ), - CastOfPointerToInt => { - ("cast of pointer to int", "casting pointers to integers in constants") - } - UseOfMutableStatic => ( - "use of mutable static", - "mutable statics can be mutated by multiple threads: aliasing violations or data \ - races will cause undefined behavior", - ), - UseOfExternStatic => ( - "use of extern static", - "extern statics are not controlled by the Rust type system: invalid data, \ - aliasing violations or data races will cause undefined behavior", - ), - DerefOfRawPointer => ( - "dereference of raw pointer", - "raw pointers may be null, dangling or unaligned; they can violate aliasing rules \ - and cause data races: all of these are undefined behavior", - ), - AccessToUnionField => ( - "access to union field", - "the field may not be properly initialized: using uninitialized data will cause \ - undefined behavior", - ), - MutationOfLayoutConstrainedField => ( - "mutation of layout constrained field", - "mutating layout constrained fields cannot statically be checked for valid values", - ), - BorrowOfLayoutConstrainedField => ( - "borrow of layout constrained field with interior mutability", - "references to fields of layout constrained fields lose the constraints. Coupled \ - with interior mutability, the field can be changed to invalid values", - ), - CallToFunctionWith => ( - "call to function with `#[target_feature]`", - "can only be called if the required target features are available", - ), - } - } -} - #[derive(Copy, Clone, PartialEq, TyEncodable, TyDecodable, HashStable, Debug)] pub struct UnsafetyViolation { pub source_info: SourceInfo, diff --git a/compiler/rustc_middle/src/traits/query.rs b/compiler/rustc_middle/src/traits/query.rs index 3cceb8b2c595..34c56eb0d7b1 100644 --- a/compiler/rustc_middle/src/traits/query.rs +++ b/compiler/rustc_middle/src/traits/query.rs @@ -108,17 +108,6 @@ impl<'tcx> DropckOutlivesResult<'tcx> { tcx.sess.emit_err(DropCheckOverflow { span, ty, overflow_ty: *overflow_ty }); } } - - pub fn into_kinds_reporting_overflows( - self, - tcx: TyCtxt<'tcx>, - span: Span, - ty: Ty<'tcx>, - ) -> Vec> { - self.report_overflows(tcx, span, ty); - let DropckOutlivesResult { kinds, overflows: _ } = self; - kinds - } } /// A set of constraints that need to be satisfied in order for diff --git a/compiler/rustc_middle/src/ty/generic_args.rs b/compiler/rustc_middle/src/ty/generic_args.rs index 0c658fa1c80f..2b8e2ee0418d 100644 --- a/compiler/rustc_middle/src/ty/generic_args.rs +++ b/compiler/rustc_middle/src/ty/generic_args.rs @@ -604,13 +604,6 @@ impl EarlyBinder> { } } -impl EarlyBinder<(T, U)> { - pub fn transpose_tuple2(self) -> (EarlyBinder, EarlyBinder) { - let EarlyBinder { value: (lhs, rhs) } = self; - (EarlyBinder { value: lhs }, EarlyBinder { value: rhs }) - } -} - impl<'tcx, 's, I: IntoIterator> EarlyBinder where I::Item: TypeFoldable>, diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 56739ce96c30..9ab02ba4ccc3 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -1301,25 +1301,6 @@ impl<'tcx> Predicate<'tcx> { } } - pub fn to_opt_type_outlives(self) -> Option> { - let predicate = self.kind(); - match predicate.skip_binder() { - PredicateKind::Clause(ClauseKind::TypeOutlives(data)) => Some(predicate.rebind(data)), - PredicateKind::Clause(ClauseKind::Trait(..)) - | PredicateKind::Clause(ClauseKind::ConstArgHasType(..)) - | PredicateKind::Clause(ClauseKind::Projection(..)) - | PredicateKind::AliasRelate(..) - | PredicateKind::Subtype(..) - | PredicateKind::Coerce(..) - | PredicateKind::Clause(ClauseKind::RegionOutlives(..)) - | PredicateKind::Clause(ClauseKind::WellFormed(..)) - | PredicateKind::ObjectSafe(..) - | PredicateKind::Clause(ClauseKind::ConstEvaluatable(..)) - | PredicateKind::ConstEquate(..) - | PredicateKind::Ambiguous => None, - } - } - /// Matches a `PredicateKind::Clause` and turns it into a `Clause`, otherwise returns `None`. pub fn as_clause(self) -> Option> { match self.kind().skip_binder() { diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index e9f65d99a2ef..97b7f9522483 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -701,22 +701,6 @@ impl<'tcx> TyCtxt<'tcx> { .map(|decl| ty::EarlyBinder::bind(decl.ty)) } - /// Normalizes all opaque types in the given value, replacing them - /// with their underlying types. - pub fn expand_opaque_types(self, val: Ty<'tcx>) -> Ty<'tcx> { - let mut visitor = OpaqueTypeExpander { - seen_opaque_tys: FxHashSet::default(), - expanded_cache: FxHashMap::default(), - primary_def_id: None, - found_recursion: false, - found_any_recursion: false, - check_recursion: false, - expand_coroutines: false, - tcx: self, - }; - val.fold_with(&mut visitor) - } - /// Expands the given impl trait type, stopping if the type is recursive. #[instrument(skip(self), level = "debug", ret)] pub fn try_expand_impl_trait_type( diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 6400ba488bb1..76be546e9455 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -139,13 +139,6 @@ pub fn set_session_globals_then(session_globals: &SessionGlobals, f: impl FnO SESSION_GLOBALS.set(session_globals, f) } -pub fn create_default_session_if_not_set_then(f: F) -> R -where - F: FnOnce(&SessionGlobals) -> R, -{ - create_session_if_not_set_then(edition::DEFAULT_EDITION, f) -} - pub fn create_session_if_not_set_then(edition: Edition, f: F) -> R where F: FnOnce(&SessionGlobals) -> R, From b06d5b205c0ef74dc7c4a169b543433c7d29de72 Mon Sep 17 00:00:00 2001 From: klensy Date: Mon, 13 Nov 2023 23:43:23 +0300 Subject: [PATCH 32/93] few more --- .../src/transform/promote_consts.rs | 33 ------------------- compiler/rustc_middle/src/ty/mod.rs | 17 ---------- .../src/traits/coherence.rs | 1 + 3 files changed, 1 insertion(+), 50 deletions(-) diff --git a/compiler/rustc_const_eval/src/transform/promote_consts.rs b/compiler/rustc_const_eval/src/transform/promote_consts.rs index 66b813e4e595..8b2ea2dc21dd 100644 --- a/compiler/rustc_const_eval/src/transform/promote_consts.rs +++ b/compiler/rustc_const_eval/src/transform/promote_consts.rs @@ -1023,36 +1023,3 @@ pub fn promote_candidates<'tcx>( promotions } - -/// This function returns `true` if the function being called in the array -/// repeat expression is a `const` function. -pub fn is_const_fn_in_array_repeat_expression<'tcx>( - ccx: &ConstCx<'_, 'tcx>, - place: &Place<'tcx>, - body: &Body<'tcx>, -) -> bool { - match place.as_local() { - // rule out cases such as: `let my_var = some_fn(); [my_var; N]` - Some(local) if body.local_decls[local].is_user_variable() => return false, - None => return false, - _ => {} - } - - for block in body.basic_blocks.iter() { - if let Some(Terminator { kind: TerminatorKind::Call { func, destination, .. }, .. }) = - &block.terminator - { - if let Operand::Constant(box ConstOperand { const_, .. }) = func { - if let ty::FnDef(def_id, _) = *const_.ty().kind() { - if destination == place { - if ccx.tcx.is_const_fn(def_id) { - return true; - } - } - } - } - } - } - - false -} diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 9ab02ba4ccc3..c2c5bb7ce5c6 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -42,7 +42,6 @@ use rustc_errors::{DiagnosticBuilder, ErrorGuaranteed, StashKey}; use rustc_hir as hir; use rustc_hir::def::{CtorKind, CtorOf, DefKind, DocLinkResMap, LifetimeRes, Res}; use rustc_hir::def_id::{CrateNum, DefId, DefIdMap, LocalDefId, LocalDefIdMap}; -use rustc_hir::Node; use rustc_index::IndexVec; use rustc_macros::HashStable; use rustc_query_system::ich::StableHashingContext; @@ -2513,22 +2512,6 @@ impl<'tcx> TyCtxt<'tcx> { } } -/// Yields the parent function's `LocalDefId` if `def_id` is an `impl Trait` definition. -pub fn is_impl_trait_defn(tcx: TyCtxt<'_>, def_id: DefId) -> Option { - let def_id = def_id.as_local()?; - if let Node::Item(item) = tcx.hir().get_by_def_id(def_id) { - if let hir::ItemKind::OpaqueTy(opaque_ty) = item.kind { - return match opaque_ty.origin { - hir::OpaqueTyOrigin::FnReturn(parent) | hir::OpaqueTyOrigin::AsyncFn(parent) => { - Some(parent) - } - hir::OpaqueTyOrigin::TyAlias { .. } => None, - }; - } - } - None -} - pub fn int_ty(ity: ast::IntTy) -> IntTy { match ity { ast::IntTy::Isize => IntTy::Isize, diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 9119792e3243..9a52ef00b74c 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -330,6 +330,7 @@ fn equate_impl_headers<'tcx>( impl1.self_ty, impl2.self_ty, ), + // FIXME: mk_eq_impl_headers fn not exist _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), }; From 57c9eb73814470d3223e4a0f4ca6ee588648ad6f Mon Sep 17 00:00:00 2001 From: klensy Date: Tue, 21 Nov 2023 16:31:40 +0300 Subject: [PATCH 33/93] review --- compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 3 +-- compiler/rustc_trait_selection/src/traits/coherence.rs | 3 +-- 2 files changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 0a15d69f474a..291b84e61d43 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -609,8 +609,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return false; } let pin_did = self.tcx.lang_items().pin_type(); - // FIXME: replace mk_box with? - // This guards the `unwrap` and `mk_box` below. + // This guards the `new_box` below. if pin_did.is_none() || self.tcx.lang_items().owned_box().is_none() { return false; } diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 9a52ef00b74c..e15d617df5d5 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -330,8 +330,7 @@ fn equate_impl_headers<'tcx>( impl1.self_ty, impl2.self_ty, ), - // FIXME: mk_eq_impl_headers fn not exist - _ => bug!("mk_eq_impl_headers given mismatched impl kinds"), + _ => bug!("equate_impl_headers given mismatched impl kinds"), }; result.map(|infer_ok| infer_ok.obligations).ok() From 4ae658683f87b0f34ffb5c06f50ca1c51333a1a4 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 23 Nov 2023 20:02:45 +0000 Subject: [PATCH 34/93] Fix fn_sig_for_fn_abi and the coroutine transform for generators There were three issues previously: * The self argument was pinned, despite Iterator::next taking an unpinned mutable reference. * A resume argument was passed, despite Iterator::next not having one. * The return value was CoroutineState rather than Option While these things just so happened to work with the LLVM backend, cg_clif does much stricter checks when trying to assign a value to a place. In addition it can't handle the mismatch between the amount of arguments specified by the FnAbi and the FnSig. --- build_system/tests.rs | 9 +++++++++ config.txt | 1 + example/gen_block_iterate.rs | 36 ++++++++++++++++++++++++++++++++++++ rustfmt.toml | 5 ++++- 4 files changed, 50 insertions(+), 1 deletion(-) create mode 100644 example/gen_block_iterate.rs diff --git a/build_system/tests.rs b/build_system/tests.rs index ff71a567ed3a..aa50dbfdf35b 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -100,6 +100,15 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]), TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"), TestCase::build_bin_and_run("aot.neon", "example/neon.rs", &[]), + TestCase::custom("aot.gen_block_iterate", &|runner| { + runner.run_rustc([ + "example/gen_block_iterate.rs", + "--edition", + "2024", + "-Zunstable-options", + ]); + runner.run_out_command("gen_block_iterate", &[]); + }), ]; pub(crate) static RAND_REPO: GitRepo = GitRepo::github( diff --git a/config.txt b/config.txt index 2ccdc7d78748..3cf295c003e4 100644 --- a/config.txt +++ b/config.txt @@ -43,6 +43,7 @@ aot.mod_bench aot.issue-72793 aot.issue-59326 aot.neon +aot.gen_block_iterate testsuite.extended_sysroot test.rust-random/rand diff --git a/example/gen_block_iterate.rs b/example/gen_block_iterate.rs new file mode 100644 index 000000000000..14bd23e77ea0 --- /dev/null +++ b/example/gen_block_iterate.rs @@ -0,0 +1,36 @@ +// Copied from https://github.com/rust-lang/rust/blob/46455dc65069387f2dc46612f13fd45452ab301a/tests/ui/coroutine/gen_block_iterate.rs +// revisions: next old +//compile-flags: --edition 2024 -Zunstable-options +//[next] compile-flags: -Ztrait-solver=next +// run-pass +#![feature(gen_blocks)] + +fn foo() -> impl Iterator { + gen { yield 42; for x in 3..6 { yield x } } +} + +fn moved() -> impl Iterator { + let mut x = "foo".to_string(); + gen move { + yield 42; + if x == "foo" { return } + x.clear(); + for x in 3..6 { yield x } + } +} + +fn main() { + let mut iter = foo(); + assert_eq!(iter.next(), Some(42)); + assert_eq!(iter.next(), Some(3)); + assert_eq!(iter.next(), Some(4)); + assert_eq!(iter.next(), Some(5)); + assert_eq!(iter.next(), None); + // `gen` blocks are fused + assert_eq!(iter.next(), None); + + let mut iter = moved(); + assert_eq!(iter.next(), Some(42)); + assert_eq!(iter.next(), None); + +} diff --git a/rustfmt.toml b/rustfmt.toml index ebeca8662a51..0f884187addd 100644 --- a/rustfmt.toml +++ b/rustfmt.toml @@ -1,4 +1,7 @@ -ignore = ["y.rs"] +ignore = [ + "y.rs", + "example/gen_block_iterate.rs", # uses edition 2024 +] # Matches rustfmt.toml of rustc version = "Two" From 430ab4e923a16fc46a6738aa4dfc2ff0c735ac9f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:22:51 +0100 Subject: [PATCH 35/93] Allow function pointers in CValue::const_val Fixes rust-lang/rustc_codegen_cranelift#1430 --- src/value_and_place.rs | 8 +++++++- 1 file changed, 7 insertions(+), 1 deletion(-) diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 21ad2a835fc9..9eb8e80d3fc2 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -329,7 +329,13 @@ impl<'tcx> CValue<'tcx> { let msb = fx.bcx.ins().iconst(types::I64, (const_val >> 64) as u64 as i64); fx.bcx.ins().iconcat(lsb, msb) } - ty::Bool | ty::Char | ty::Uint(_) | ty::Int(_) | ty::Ref(..) | ty::RawPtr(..) => { + ty::Bool + | ty::Char + | ty::Uint(_) + | ty::Int(_) + | ty::Ref(..) + | ty::RawPtr(..) + | ty::FnPtr(..) => { let raw_val = const_val.size().truncate(const_val.to_bits(layout.size).unwrap()); fx.bcx.ins().iconst(clif_ty, raw_val as i64) } From 9c958196e717744257e40623ca6598b82e050b9f Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 24 Nov 2023 10:46:22 +0100 Subject: [PATCH 36/93] Fix polymorphization for coroutines Fixes rust-lang/rustc_codegen_cranelift#1429 --- build_system/tests.rs | 4 ++++ config.txt | 1 + example/polymorphize_coroutine.rs | 16 ++++++++++++++++ src/value_and_place.rs | 26 ++++++++++++++++++++++++++ 4 files changed, 47 insertions(+) create mode 100644 example/polymorphize_coroutine.rs diff --git a/build_system/tests.rs b/build_system/tests.rs index f6e6ac6f1e8e..4cc572f0abaf 100644 --- a/build_system/tests.rs +++ b/build_system/tests.rs @@ -99,6 +99,10 @@ const BASE_SYSROOT_SUITE: &[TestCase] = &[ TestCase::build_bin_and_run("aot.mod_bench", "example/mod_bench.rs", &[]), TestCase::build_bin_and_run("aot.issue-72793", "example/issue-72793.rs", &[]), TestCase::build_bin("aot.issue-59326", "example/issue-59326.rs"), + TestCase::custom("aot.polymorphize_coroutine", &|runner| { + runner.run_rustc(&["example/polymorphize_coroutine.rs", "-Zpolymorphize"]); + runner.run_out_command("polymorphize_coroutine", &[]); + }), TestCase::build_bin_and_run("aot.neon", "example/neon.rs", &[]), ]; diff --git a/config.txt b/config.txt index 2ccdc7d78748..79284df6b196 100644 --- a/config.txt +++ b/config.txt @@ -42,6 +42,7 @@ aot.float-minmax-pass aot.mod_bench aot.issue-72793 aot.issue-59326 +aot.polymorphize_coroutine aot.neon testsuite.extended_sysroot diff --git a/example/polymorphize_coroutine.rs b/example/polymorphize_coroutine.rs new file mode 100644 index 000000000000..c965b34e13b9 --- /dev/null +++ b/example/polymorphize_coroutine.rs @@ -0,0 +1,16 @@ +#![feature(coroutines, coroutine_trait)] + +use std::ops::Coroutine; +use std::pin::Pin; + +fn main() { + run_coroutine::(); +} + +fn run_coroutine() { + let mut coroutine = || { + yield; + return; + }; + Pin::new(&mut coroutine).resume(()); +} diff --git a/src/value_and_place.rs b/src/value_and_place.rs index 9eb8e80d3fc2..f52f59716a8a 100644 --- a/src/value_and_place.rs +++ b/src/value_and_place.rs @@ -977,6 +977,32 @@ pub(crate) fn assert_assignable<'tcx>( } } } + (&ty::Coroutine(def_id_a, args_a, mov_a), &ty::Coroutine(def_id_b, args_b, mov_b)) + if def_id_a == def_id_b && mov_a == mov_b => + { + let mut types_a = args_a.types(); + let mut types_b = args_b.types(); + loop { + match (types_a.next(), types_b.next()) { + (Some(a), Some(b)) => assert_assignable(fx, a, b, limit - 1), + (None, None) => return, + (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty), + } + } + } + (&ty::CoroutineWitness(def_id_a, args_a), &ty::CoroutineWitness(def_id_b, args_b)) + if def_id_a == def_id_b => + { + let mut types_a = args_a.types(); + let mut types_b = args_b.types(); + loop { + match (types_a.next(), types_b.next()) { + (Some(a), Some(b)) => assert_assignable(fx, a, b, limit - 1), + (None, None) => return, + (Some(_), None) | (None, Some(_)) => panic!("{:#?}/{:#?}", from_ty, to_ty), + } + } + } (ty::Param(_), _) | (_, ty::Param(_)) if fx.tcx.sess.opts.unstable_opts.polymorphize => { // No way to check if it is correct or not with polymorphization enabled } From 3ec8d7aa4a05c3286189441abef0ce757d03b4b5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sun, 12 Nov 2023 17:57:35 +0000 Subject: [PATCH 37/93] Implement _mm_cmpestri and _mm_cmpestrm using inline asm --- src/intrinsics/llvm_x86.rs | 98 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 98 insertions(+) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 78a0a347cfc2..0fa46b1dac26 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -720,6 +720,104 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( } } + "llvm.x86.sse42.pcmpestri128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestri&ig_expand=939 + intrinsic_args!(fx, args => (a, la, b, lb, _imm8); intrinsic); + + let a = a.load_scalar(fx); + let la = la.load_scalar(fx); + let b = b.load_scalar(fx); + let lb = lb.load_scalar(fx); + + let imm8 = if let Some(imm8) = crate::constant::mir_operand_get_const_val(fx, &args[4]) + { + imm8 + } else { + fx.tcx.sess.span_fatal(span, "Index argument for `_mm_cmpestri` is not a constant"); + }; + + let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8)); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String(format!("pcmpestri xmm0, xmm1, {imm8}"))], + &[ + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + value: a, + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)), + value: b, + }, + // Implicit argument to the pcmpestri intrinsic + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)), + value: la, + }, + // Implicit argument to the pcmpestri intrinsic + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)), + value: lb, + }, + // Implicit result of the pcmpestri intrinsic + CInlineAsmOperand::Out { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::cx)), + late: true, + place: Some(ret), + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + + "llvm.x86.sse42.pcmpestrm128" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestrm&ig_expand=940 + intrinsic_args!(fx, args => (a, la, b, lb, _imm8); intrinsic); + + let a = a.load_scalar(fx); + let la = la.load_scalar(fx); + let b = b.load_scalar(fx); + let lb = lb.load_scalar(fx); + + let imm8 = if let Some(imm8) = crate::constant::mir_operand_get_const_val(fx, &args[4]) + { + imm8 + } else { + fx.tcx.sess.span_fatal(span, "Index argument for `_mm_cmpestrm` is not a constant"); + }; + + let imm8 = imm8.try_to_u8().unwrap_or_else(|_| panic!("kind not scalar: {:?}", imm8)); + + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String(format!("pcmpestrm xmm0, xmm1, {imm8}"))], + &[ + CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + _late: true, + in_value: a, + out_place: Some(ret), + }, + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm1)), + value: b, + }, + // Implicit argument to the pcmpestri intrinsic + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::ax)), + value: la, + }, + // Implicit argument to the pcmpestri intrinsic + CInlineAsmOperand::In { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::dx)), + value: lb, + }, + ], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } + "llvm.x86.pclmulqdq" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_clmulepi64_si128&ig_expand=772 intrinsic_args!(fx, args => (a, b, _imm8); intrinsic); From 705031d0177af0b492a3224c01bda257c85505e6 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 24 Nov 2023 13:57:21 +0000 Subject: [PATCH 38/93] Implement _mm_cvttps_epi32 --- src/intrinsics/llvm_x86.rs | 25 ++++++++++++++++++++----- 1 file changed, 20 insertions(+), 5 deletions(-) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 0fa46b1dac26..85ce94099986 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -273,16 +273,31 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( ); } "llvm.x86.ssse3.pabs.b.128" | "llvm.x86.ssse3.pabs.w.128" | "llvm.x86.ssse3.pabs.d.128" => { - let a = match args { - [a] => a, - _ => bug!("wrong number of args for intrinsic {intrinsic}"), - }; - let a = codegen_operand(fx, a); + intrinsic_args!(fx, args => (a); intrinsic); simd_for_each_lane(fx, a, ret, &|fx, _lane_ty, _res_lane_ty, lane| { fx.bcx.ins().iabs(lane) }); } + "llvm.x86.sse2.cvttps2dq" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cvttps_epi32&ig_expand=2429 + intrinsic_args!(fx, args => (a); intrinsic); + let a = a.load_scalar(fx); + + // Using inline asm instead of fcvt_to_sint_sat as unrepresentable values are turned + // into 0x80000000 for which Cranelift doesn't have a native instruction. + codegen_inline_asm_inner( + fx, + &[InlineAsmTemplatePiece::String(format!("cvttps2dq xmm0, xmm0"))], + &[CInlineAsmOperand::InOut { + reg: InlineAsmRegOrRegClass::Reg(InlineAsmReg::X86(X86InlineAsmReg::xmm0)), + _late: true, + in_value: a, + out_place: Some(ret), + }], + InlineAsmOptions::NOSTACK | InlineAsmOptions::PURE | InlineAsmOptions::NOMEM, + ); + } "llvm.x86.addcarry.32" | "llvm.x86.addcarry.64" => { intrinsic_args!(fx, args => (c_in, a, b); intrinsic); let c_in = c_in.load_scalar(fx); From 65da67169427a3b09726b64389d827aa7b2bfbe8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 24 Nov 2023 15:30:53 +0000 Subject: [PATCH 39/93] Implement *fmaddsub_p*, *fmsubadd_p* and *fnmadd_p* vendor intrinsics --- src/intrinsics/llvm_x86.rs | 111 +++++++++++++++++++++++++++++++++++++ 1 file changed, 111 insertions(+) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 85ce94099986..142ca1cf5dd0 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -735,6 +735,117 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( } } + "llvm.x86.fma.vfmaddsub.ps" + | "llvm.x86.fma.vfmaddsub.pd" + | "llvm.x86.fma.vfmaddsub.ps.256" + | "llvm.x86.fma.vfmaddsub.pd.256" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmaddsub_ps&ig_expand=3205 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmaddsub_pd&ig_expand=3181 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmaddsub_ps&ig_expand=3209 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmaddsub_pd&ig_expand=3185 + intrinsic_args!(fx, args => (a, b, c); intrinsic); + + assert_eq!(a.layout(), b.layout()); + assert_eq!(a.layout(), c.layout()); + let layout = a.layout(); + + let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + assert!(lane_ty.is_floating_point()); + assert!(ret_lane_ty.is_floating_point()); + assert_eq!(lane_count, ret_lane_count); + let ret_lane_layout = fx.layout_of(ret_lane_ty); + + for idx in 0..lane_count { + let a_lane = a.value_lane(fx, idx).load_scalar(fx); + let b_lane = b.value_lane(fx, idx).load_scalar(fx); + let c_lane = c.value_lane(fx, idx).load_scalar(fx); + + let mul = fx.bcx.ins().fmul(a_lane, b_lane); + let res = if idx & 1 == 0 { + fx.bcx.ins().fsub(mul, c_lane) + } else { + fx.bcx.ins().fadd(mul, c_lane) + }; + + let res_lane = CValue::by_val(res, ret_lane_layout); + ret.place_lane(fx, idx).write_cvalue(fx, res_lane); + } + } + + "llvm.x86.fma.vfmsubadd.ps" + | "llvm.x86.fma.vfmsubadd.pd" + | "llvm.x86.fma.vfmsubadd.ps.256" + | "llvm.x86.fma.vfmsubadd.pd.256" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmsubadd_ps&ig_expand=3325 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fmsubadd_pd&ig_expand=3301 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmsubadd_ps&ig_expand=3329 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fmsubadd_pd&ig_expand=3305 + intrinsic_args!(fx, args => (a, b, c); intrinsic); + + assert_eq!(a.layout(), b.layout()); + assert_eq!(a.layout(), c.layout()); + let layout = a.layout(); + + let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + assert!(lane_ty.is_floating_point()); + assert!(ret_lane_ty.is_floating_point()); + assert_eq!(lane_count, ret_lane_count); + let ret_lane_layout = fx.layout_of(ret_lane_ty); + + for idx in 0..lane_count { + let a_lane = a.value_lane(fx, idx).load_scalar(fx); + let b_lane = b.value_lane(fx, idx).load_scalar(fx); + let c_lane = c.value_lane(fx, idx).load_scalar(fx); + + let mul = fx.bcx.ins().fmul(a_lane, b_lane); + let res = if idx & 1 == 0 { + fx.bcx.ins().fadd(mul, c_lane) + } else { + fx.bcx.ins().fsub(mul, c_lane) + }; + + let res_lane = CValue::by_val(res, ret_lane_layout); + ret.place_lane(fx, idx).write_cvalue(fx, res_lane); + } + } + + "llvm.x86.fma.vfnmadd.ps" + | "llvm.x86.fma.vfnmadd.pd" + | "llvm.x86.fma.vfnmadd.ps.256" + | "llvm.x86.fma.vfnmadd.pd.256" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fnmadd_ps&ig_expand=3391 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_fnmadd_pd&ig_expand=3367 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fnmadd_ps&ig_expand=3395 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_fnmadd_pd&ig_expand=3371 + intrinsic_args!(fx, args => (a, b, c); intrinsic); + + assert_eq!(a.layout(), b.layout()); + assert_eq!(a.layout(), c.layout()); + let layout = a.layout(); + + let (lane_count, lane_ty) = layout.ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + assert!(lane_ty.is_floating_point()); + assert!(ret_lane_ty.is_floating_point()); + assert_eq!(lane_count, ret_lane_count); + let ret_lane_layout = fx.layout_of(ret_lane_ty); + + for idx in 0..lane_count { + let a_lane = a.value_lane(fx, idx).load_scalar(fx); + let b_lane = b.value_lane(fx, idx).load_scalar(fx); + let c_lane = c.value_lane(fx, idx).load_scalar(fx); + + let mul = fx.bcx.ins().fmul(a_lane, b_lane); + let neg_mul = fx.bcx.ins().fneg(mul); + let res = fx.bcx.ins().fadd(neg_mul, c_lane); + + let res_lane = CValue::by_val(res, ret_lane_layout); + ret.place_lane(fx, idx).write_cvalue(fx, res_lane); + } + } + "llvm.x86.sse42.pcmpestri128" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_cmpestri&ig_expand=939 intrinsic_args!(fx, args => (a, la, b, lb, _imm8); intrinsic); From c8729e9216bda2b51d8781d95cae0b907e71c6b8 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 24 Nov 2023 15:31:14 +0000 Subject: [PATCH 40/93] Implement _mm256_zeroupper vendor intrinsic --- src/intrinsics/llvm_x86.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 142ca1cf5dd0..f85f9b8917eb 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -22,6 +22,11 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( // Spin loop hint } + "llvm.x86.avx.vzeroupper" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_zeroupper&ig_expand=7218 + // Do nothing. It is a perf hint anyway. + } + // Used by is_x86_feature_detected!(); "llvm.x86.xgetbv" => { intrinsic_args!(fx, args => (xcr_no); intrinsic); From d5a7ae7976ec02196ec9893f79fa06612059dfbc Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 24 Nov 2023 19:26:46 +0000 Subject: [PATCH 41/93] Implement the float part of the gather family vendor intrinsics --- src/intrinsics/llvm_x86.rs | 87 ++++++++++++++++++++++++++++++++++++++ 1 file changed, 87 insertions(+) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index f85f9b8917eb..6cccc8b8396d 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -74,6 +74,93 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( ret.write_cvalue(fx, val); } + "llvm.x86.avx2.gather.d.ps" + | "llvm.x86.avx2.gather.d.pd" + | "llvm.x86.avx2.gather.d.ps.256" + | "llvm.x86.avx2.gather.d.pd.256" + | "llvm.x86.avx2.gather.q.ps" + | "llvm.x86.avx2.gather.q.pd" + | "llvm.x86.avx2.gather.q.ps.256" + | "llvm.x86.avx2.gather.q.pd.256" => { + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_i64gather_pd&ig_expand=3818 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_mask_i64gather_pd&ig_expand=3819 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_i64gather_pd&ig_expand=3821 + // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm256_mask_i64gather_pd&ig_expand=3822 + // ... + + intrinsic_args!(fx, args => (src, ptr, index, mask, scale); intrinsic); + + let (src_lane_count, src_lane_ty) = src.layout().ty.simd_size_and_type(fx.tcx); + let (index_lane_count, index_lane_ty) = index.layout().ty.simd_size_and_type(fx.tcx); + let (mask_lane_count, mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx); + let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); + assert!(src_lane_ty.is_floating_point()); + assert!(index_lane_ty.is_integral()); + assert!(mask_lane_ty.is_floating_point()); + assert!(ret_lane_ty.is_floating_point()); + assert_eq!(src_lane_count, mask_lane_count); + assert_eq!(src_lane_count, ret_lane_count); + + let lane_clif_ty = fx.clif_type(ret_lane_ty).unwrap(); + let index_lane_clif_ty = fx.clif_type(index_lane_ty).unwrap(); + let mask_lane_clif_ty = fx.clif_type(mask_lane_ty).unwrap(); + let ret_lane_layout = fx.layout_of(ret_lane_ty); + + let ptr = ptr.load_scalar(fx); + let scale = scale.load_scalar(fx); + let scale = fx.bcx.ins().uextend(types::I64, scale); + for lane_idx in 0..std::cmp::min(src_lane_count, index_lane_count) { + let src_lane = src.value_lane(fx, lane_idx).load_scalar(fx); + let index_lane = index.value_lane(fx, lane_idx).load_scalar(fx); + let mask_lane = mask.value_lane(fx, lane_idx).load_scalar(fx); + let mask_lane = + fx.bcx.ins().bitcast(mask_lane_clif_ty.as_int(), MemFlags::new(), mask_lane); + + let if_enabled = fx.bcx.create_block(); + let if_disabled = fx.bcx.create_block(); + let next = fx.bcx.create_block(); + let res_lane = fx.bcx.append_block_param(next, lane_clif_ty); + + let mask_lane = match mask_lane_clif_ty { + types::F32 => fx.bcx.ins().band_imm(mask_lane, 0x8000_0000u64 as i64), + types::F64 => fx.bcx.ins().band_imm(mask_lane, 0x8000_0000_0000_0000u64 as i64), + _ => unreachable!(), + }; + fx.bcx.ins().brif(mask_lane, if_enabled, &[], if_disabled, &[]); + fx.bcx.seal_block(if_enabled); + fx.bcx.seal_block(if_disabled); + + fx.bcx.switch_to_block(if_enabled); + let index_lane = if index_lane_clif_ty != types::I64 { + fx.bcx.ins().sextend(types::I64, index_lane) + } else { + index_lane + }; + let offset = fx.bcx.ins().imul(index_lane, scale); + let lane_ptr = fx.bcx.ins().iadd(ptr, offset); + let res = fx.bcx.ins().load(lane_clif_ty, MemFlags::trusted(), lane_ptr, 0); + fx.bcx.ins().jump(next, &[res]); + + fx.bcx.switch_to_block(if_disabled); + fx.bcx.ins().jump(next, &[src_lane]); + + fx.bcx.seal_block(next); + fx.bcx.switch_to_block(next); + + fx.bcx.ins().nop(); + + ret.place_lane(fx, lane_idx) + .write_cvalue(fx, CValue::by_val(res_lane, ret_lane_layout)); + } + + for lane_idx in std::cmp::min(src_lane_count, index_lane_count)..ret_lane_count { + let zero_lane = fx.bcx.ins().iconst(mask_lane_clif_ty.as_int(), 0); + let zero_lane = fx.bcx.ins().bitcast(mask_lane_clif_ty, MemFlags::new(), zero_lane); + ret.place_lane(fx, lane_idx) + .write_cvalue(fx, CValue::by_val(zero_lane, ret_lane_layout)); + } + } + "llvm.x86.sse.cmp.ps" | "llvm.x86.sse2.cmp.pd" => { let (x, y, kind) = match args { [x, y, kind] => (x, y, kind), From 3b49b9efd5e91b3104bc377ab64ee88aaa3ce31d Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Fri, 24 Nov 2023 19:38:13 +0000 Subject: [PATCH 42/93] Implement the int part of the gather family vendor intrinsics --- src/intrinsics/llvm_x86.rs | 22 ++++++++++++++++------ 1 file changed, 16 insertions(+), 6 deletions(-) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 6cccc8b8396d..2108b4bb9ffe 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -74,12 +74,20 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( ret.write_cvalue(fx, val); } - "llvm.x86.avx2.gather.d.ps" + "llvm.x86.avx2.gather.d.d" + | "llvm.x86.avx2.gather.d.q" + | "llvm.x86.avx2.gather.d.ps" | "llvm.x86.avx2.gather.d.pd" + | "llvm.x86.avx2.gather.d.d.256" + | "llvm.x86.avx2.gather.d.q.256" | "llvm.x86.avx2.gather.d.ps.256" | "llvm.x86.avx2.gather.d.pd.256" + | "llvm.x86.avx2.gather.q.d" + | "llvm.x86.avx2.gather.q.q" | "llvm.x86.avx2.gather.q.ps" | "llvm.x86.avx2.gather.q.pd" + | "llvm.x86.avx2.gather.q.d.256" + | "llvm.x86.avx2.gather.q.q.256" | "llvm.x86.avx2.gather.q.ps.256" | "llvm.x86.avx2.gather.q.pd.256" => { // https://www.intel.com/content/www/us/en/docs/intrinsics-guide/index.html#text=_mm_i64gather_pd&ig_expand=3818 @@ -94,10 +102,8 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( let (index_lane_count, index_lane_ty) = index.layout().ty.simd_size_and_type(fx.tcx); let (mask_lane_count, mask_lane_ty) = mask.layout().ty.simd_size_and_type(fx.tcx); let (ret_lane_count, ret_lane_ty) = ret.layout().ty.simd_size_and_type(fx.tcx); - assert!(src_lane_ty.is_floating_point()); + assert_eq!(src_lane_ty, ret_lane_ty); assert!(index_lane_ty.is_integral()); - assert!(mask_lane_ty.is_floating_point()); - assert!(ret_lane_ty.is_floating_point()); assert_eq!(src_lane_count, mask_lane_count); assert_eq!(src_lane_count, ret_lane_count); @@ -122,8 +128,12 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( let res_lane = fx.bcx.append_block_param(next, lane_clif_ty); let mask_lane = match mask_lane_clif_ty { - types::F32 => fx.bcx.ins().band_imm(mask_lane, 0x8000_0000u64 as i64), - types::F64 => fx.bcx.ins().band_imm(mask_lane, 0x8000_0000_0000_0000u64 as i64), + types::I32 | types::F32 => { + fx.bcx.ins().band_imm(mask_lane, 0x8000_0000u64 as i64) + } + types::I64 | types::F64 => { + fx.bcx.ins().band_imm(mask_lane, 0x8000_0000_0000_0000u64 as i64) + } _ => unreachable!(), }; fx.bcx.ins().brif(mask_lane, if_enabled, &[], if_disabled, &[]); From 0750a5df4d1d04f95e117939493af4713fa71d2e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 24 Nov 2023 18:10:30 +0000 Subject: [PATCH 43/93] AmbiguityCause should not eagerly format strings --- .../src/traits/coherence.rs | 39 ++++----- .../src/traits/select/mod.rs | 84 +++++++++---------- .../src/traits/specialize/mod.rs | 2 +- 3 files changed, 56 insertions(+), 69 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index 9119792e3243..ed55d5267d14 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -29,7 +29,6 @@ use rustc_middle::traits::solve::{CandidateSource, Certainty, Goal}; use rustc_middle::traits::specialization_graph::OverlapMode; use rustc_middle::traits::DefiningAnchor; use rustc_middle::ty::fast_reject::{DeepRejectCtxt, TreatParams}; -use rustc_middle::ty::print::with_no_trimmed_paths; use rustc_middle::ty::visit::{TypeVisitable, TypeVisitableExt}; use rustc_middle::ty::{self, Ty, TyCtxt, TypeSuperVisitable, TypeVisitor}; use rustc_session::lint::builtin::COINDUCTIVE_OVERLAP_IN_COHERENCE; @@ -54,7 +53,7 @@ pub enum Conflict { pub struct OverlapResult<'tcx> { pub impl_header: ty::ImplHeader<'tcx>, - pub intercrate_ambiguity_causes: FxIndexSet, + pub intercrate_ambiguity_causes: FxIndexSet>, /// `true` if the overlap might've been permitted before the shift /// to universes. @@ -979,8 +978,8 @@ where fn compute_intercrate_ambiguity_causes<'tcx>( infcx: &InferCtxt<'tcx>, obligations: &[PredicateObligation<'tcx>], -) -> FxIndexSet { - let mut causes: FxIndexSet = Default::default(); +) -> FxIndexSet> { + let mut causes: FxIndexSet> = Default::default(); for obligation in obligations { search_ambiguity_causes(infcx, obligation.clone().into(), &mut causes); @@ -989,11 +988,11 @@ fn compute_intercrate_ambiguity_causes<'tcx>( causes } -struct AmbiguityCausesVisitor<'a> { - causes: &'a mut FxIndexSet, +struct AmbiguityCausesVisitor<'a, 'tcx> { + causes: &'a mut FxIndexSet>, } -impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> { +impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a, 'tcx> { type BreakTy = !; fn visit_goal(&mut self, goal: &InspectGoal<'_, 'tcx>) -> ControlFlow { let infcx = goal.infcx(); @@ -1033,14 +1032,12 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> { } = cand.kind() { if let ty::ImplPolarity::Reservation = infcx.tcx.impl_polarity(def_id) { - let value = infcx + let message = infcx .tcx .get_attr(def_id, sym::rustc_reservation_impl) .and_then(|a| a.value_str()); - if let Some(value) = value { - self.causes.insert(IntercrateAmbiguityCause::ReservationImpl { - message: value.to_string(), - }); + if let Some(message) = message { + self.causes.insert(IntercrateAmbiguityCause::ReservationImpl { message }); } } } @@ -1078,24 +1075,18 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> { Ok(Err(conflict)) => { if !trait_ref.references_error() { let self_ty = trait_ref.self_ty(); - let (trait_desc, self_desc) = with_no_trimmed_paths!({ - let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = self_ty - .has_concrete_skeleton() - .then(|| self_ty.to_string()); - (trait_desc, self_desc) - }); + let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty); ambiguity_cause = Some(match conflict { Conflict::Upstream => { IntercrateAmbiguityCause::UpstreamCrateUpdate { - trait_desc, - self_desc, + trait_ref, + self_ty, } } Conflict::Downstream => { IntercrateAmbiguityCause::DownstreamCrate { - trait_desc, - self_desc, + trait_ref, + self_ty, } } }); @@ -1132,7 +1123,7 @@ impl<'a, 'tcx> ProofTreeVisitor<'tcx> for AmbiguityCausesVisitor<'a> { fn search_ambiguity_causes<'tcx>( infcx: &InferCtxt<'tcx>, goal: Goal<'tcx, ty::Predicate<'tcx>>, - causes: &mut FxIndexSet, + causes: &mut FxIndexSet>, ) { infcx.visit_proof_tree(goal, &mut AmbiguityCausesVisitor { causes }); } diff --git a/compiler/rustc_trait_selection/src/traits/select/mod.rs b/compiler/rustc_trait_selection/src/traits/select/mod.rs index f3e6887e012b..0c884b7c16a8 100644 --- a/compiler/rustc_trait_selection/src/traits/select/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/select/mod.rs @@ -46,6 +46,7 @@ use rustc_middle::ty::GenericArgsRef; use rustc_middle::ty::{self, EarlyBinder, PolyProjectionPredicate, ToPolyTraitRef, ToPredicate}; use rustc_middle::ty::{Ty, TyCtxt, TypeFoldable, TypeVisitableExt}; use rustc_span::symbol::sym; +use rustc_span::Symbol; use std::cell::{Cell, RefCell}; use std::cmp; @@ -59,13 +60,13 @@ mod candidate_assembly; mod confirmation; #[derive(Clone, Debug, Eq, PartialEq, Hash)] -pub enum IntercrateAmbiguityCause { - DownstreamCrate { trait_desc: String, self_desc: Option }, - UpstreamCrateUpdate { trait_desc: String, self_desc: Option }, - ReservationImpl { message: String }, +pub enum IntercrateAmbiguityCause<'tcx> { + DownstreamCrate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option> }, + UpstreamCrateUpdate { trait_ref: ty::TraitRef<'tcx>, self_ty: Option> }, + ReservationImpl { message: Symbol }, } -impl IntercrateAmbiguityCause { +impl<'tcx> IntercrateAmbiguityCause<'tcx> { /// Emits notes when the overlap is caused by complex intercrate ambiguities. /// See #23980 for details. pub fn add_intercrate_ambiguity_hint(&self, err: &mut Diagnostic) { @@ -73,28 +74,32 @@ impl IntercrateAmbiguityCause { } pub fn intercrate_ambiguity_hint(&self) -> String { - match self { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } => { - let self_desc = if let Some(ty) = self_desc { - format!(" for type `{ty}`") - } else { - String::new() - }; - format!("downstream crates may implement trait `{trait_desc}`{self_desc}") - } - IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_desc, self_desc } => { - let self_desc = if let Some(ty) = self_desc { - format!(" for type `{ty}`") - } else { - String::new() - }; + with_no_trimmed_paths!(match self { + IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } => { format!( - "upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \ - in future versions" + "downstream crates may implement trait `{trait_desc}`{self_desc}", + trait_desc = trait_ref.print_only_trait_path(), + self_desc = if let Some(self_ty) = self_ty { + format!(" for type `{self_ty}`") + } else { + String::new() + } ) } - IntercrateAmbiguityCause::ReservationImpl { message } => message.clone(), - } + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty } => { + format!( + "upstream crates may add a new impl of trait `{trait_desc}`{self_desc} \ + in future versions", + trait_desc = trait_ref.print_only_trait_path(), + self_desc = if let Some(self_ty) = self_ty { + format!(" for type `{self_ty}`") + } else { + String::new() + } + ) + } + IntercrateAmbiguityCause::ReservationImpl { message } => message.to_string(), + }) } } @@ -114,7 +119,7 @@ pub struct SelectionContext<'cx, 'tcx> { /// We don't do his until we detect a coherence error because it can /// lead to false overflow results (#47139) and because always /// computing it may negatively impact performance. - intercrate_ambiguity_causes: Option>, + intercrate_ambiguity_causes: Option>>, /// The mode that trait queries run in, which informs our error handling /// policy. In essence, canonicalized queries need their errors propagated @@ -270,7 +275,9 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { /// Gets the intercrate ambiguity causes collected since tracking /// was enabled and disables tracking at the same time. If /// tracking is not enabled, just returns an empty vector. - pub fn take_intercrate_ambiguity_causes(&mut self) -> FxIndexSet { + pub fn take_intercrate_ambiguity_causes( + &mut self, + ) -> FxIndexSet> { assert!(self.is_intercrate()); self.intercrate_ambiguity_causes.take().unwrap_or_default() } @@ -428,19 +435,11 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { ); if !trait_ref.references_error() { let self_ty = trait_ref.self_ty(); - let (trait_desc, self_desc) = with_no_trimmed_paths!({ - let trait_desc = trait_ref.print_only_trait_path().to_string(); - let self_desc = - self_ty.has_concrete_skeleton().then(|| self_ty.to_string()); - (trait_desc, self_desc) - }); + let self_ty = self_ty.has_concrete_skeleton().then(|| self_ty); let cause = if let Conflict::Upstream = conflict { - IntercrateAmbiguityCause::UpstreamCrateUpdate { - trait_desc, - self_desc, - } + IntercrateAmbiguityCause::UpstreamCrateUpdate { trait_ref, self_ty } } else { - IntercrateAmbiguityCause::DownstreamCrate { trait_desc, self_desc } + IntercrateAmbiguityCause::DownstreamCrate { trait_ref, self_ty } }; debug!(?cause, "evaluate_stack: pushing cause"); self.intercrate_ambiguity_causes.as_mut().unwrap().insert(cause); @@ -1451,20 +1450,17 @@ impl<'cx, 'tcx> SelectionContext<'cx, 'tcx> { if let ImplCandidate(def_id) = candidate { if let ty::ImplPolarity::Reservation = tcx.impl_polarity(def_id) { if let Some(intercrate_ambiguity_clauses) = &mut self.intercrate_ambiguity_causes { - let value = tcx + let message = tcx .get_attr(def_id, sym::rustc_reservation_impl) .and_then(|a| a.value_str()); - if let Some(value) = value { + if let Some(message) = message { debug!( "filter_reservation_impls: \ reservation impl ambiguity on {:?}", def_id ); - intercrate_ambiguity_clauses.insert( - IntercrateAmbiguityCause::ReservationImpl { - message: value.to_string(), - }, - ); + intercrate_ambiguity_clauses + .insert(IntercrateAmbiguityCause::ReservationImpl { message }); } } return Ok(None); diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 0f7a0ab17ef1..a3f6470fd37d 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -37,7 +37,7 @@ pub struct OverlapError<'tcx> { pub with_impl: DefId, pub trait_ref: ty::TraitRef<'tcx>, pub self_ty: Option>, - pub intercrate_ambiguity_causes: FxIndexSet, + pub intercrate_ambiguity_causes: FxIndexSet>, pub involves_placeholder: bool, } From ad0770eeee26ff4b38bd643044d702c236a08901 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 24 Nov 2023 23:39:42 +0300 Subject: [PATCH 44/93] resolve: Avoid clones of `MacroData` And move declarative macro compilation to an earlier point in def collector, which is required for #118188. --- .../rustc_resolve/src/build_reduced_graph.rs | 55 +++++++------------ compiler/rustc_resolve/src/def_collector.rs | 9 ++- compiler/rustc_resolve/src/ident.rs | 2 +- compiler/rustc_resolve/src/lib.rs | 18 ++++-- compiler/rustc_resolve/src/macros.rs | 23 ++++---- 5 files changed, 52 insertions(+), 55 deletions(-) diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 0b1a43f32826..60a28e3a1a4b 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -156,33 +156,26 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - pub(crate) fn get_macro(&mut self, res: Res) -> Option { + pub(crate) fn get_macro(&mut self, res: Res) -> Option<&MacroData> { match res { Res::Def(DefKind::Macro(..), def_id) => Some(self.get_macro_by_def_id(def_id)), - Res::NonMacroAttr(_) => { - Some(MacroData { ext: self.non_macro_attr.clone(), macro_rules: false }) - } + Res::NonMacroAttr(_) => Some(&self.non_macro_attr), _ => None, } } - pub(crate) fn get_macro_by_def_id(&mut self, def_id: DefId) -> MacroData { - if let Some(macro_data) = self.macro_map.get(&def_id) { - return macro_data.clone(); + pub(crate) fn get_macro_by_def_id(&mut self, def_id: DefId) -> &MacroData { + if self.macro_map.contains_key(&def_id) { + return &self.macro_map[&def_id]; } - let load_macro_untracked = self.cstore().load_macro_untracked(def_id, self.tcx); - let (ext, macro_rules) = match load_macro_untracked { - LoadedMacro::MacroDef(item, edition) => ( - Lrc::new(self.compile_macro(&item, edition).0), - matches!(item.kind, ItemKind::MacroDef(def) if def.macro_rules), - ), - LoadedMacro::ProcMacro(extz) => (Lrc::new(extz), false), + let loaded_macro = self.cstore().load_macro_untracked(def_id, self.tcx); + let macro_data = match loaded_macro { + LoadedMacro::MacroDef(item, edition) => self.compile_macro(&item, edition), + LoadedMacro::ProcMacro(ext) => MacroData::new(Lrc::new(ext)), }; - let macro_data = MacroData { ext, macro_rules }; - self.macro_map.insert(def_id, macro_data.clone()); - macro_data + self.macro_map.entry(def_id).or_insert(macro_data) } pub(crate) fn build_reduced_graph( @@ -1175,16 +1168,10 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { // Mark the given macro as unused unless its name starts with `_`. // Macro uses will remove items from this set, and the remaining // items will be reported as `unused_macros`. - fn insert_unused_macro( - &mut self, - ident: Ident, - def_id: LocalDefId, - node_id: NodeId, - rule_spans: &[(usize, Span)], - ) { + fn insert_unused_macro(&mut self, ident: Ident, def_id: LocalDefId, node_id: NodeId) { if !ident.as_str().starts_with('_') { self.r.unused_macros.insert(def_id, (node_id, ident)); - for (rule_i, rule_span) in rule_spans.iter() { + for (rule_i, rule_span) in &self.r.macro_map[&def_id.to_def_id()].rule_spans { self.r.unused_macro_rules.insert((def_id, *rule_i), (ident, *rule_span)); } } @@ -1194,24 +1181,24 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { let parent_scope = self.parent_scope; let expansion = parent_scope.expansion; let def_id = self.r.local_def_id(item.id); - let (ext, ident, span, macro_rules, rule_spans) = match &item.kind { + let (macro_kind, ident, span, macro_rules) = match &item.kind { ItemKind::MacroDef(def) => { - let (ext, rule_spans) = self.r.compile_macro(item, self.r.tcx.sess.edition()); - let ext = Lrc::new(ext); - (ext, item.ident, item.span, def.macro_rules, rule_spans) + let macro_kind = self.r.macro_map[&def_id.to_def_id()].ext.macro_kind(); + (macro_kind, item.ident, item.span, def.macro_rules) } ItemKind::Fn(..) => match self.proc_macro_stub(item) { Some((macro_kind, ident, span)) => { + let macro_data = MacroData::new(self.r.dummy_ext(macro_kind)); + self.r.macro_map.insert(def_id.to_def_id(), macro_data); self.r.proc_macro_stubs.insert(def_id); - (self.r.dummy_ext(macro_kind), ident, span, false, Vec::new()) + (macro_kind, ident, span, false) } None => return parent_scope.macro_rules, }, _ => unreachable!(), }; - let res = Res::Def(DefKind::Macro(ext.macro_kind()), def_id.to_def_id()); - self.r.macro_map.insert(def_id.to_def_id(), MacroData { ext, macro_rules }); + let res = Res::Def(DefKind::Macro(macro_kind), def_id.to_def_id()); self.r.local_macro_def_scopes.insert(def_id, parent_scope.module); if macro_rules { @@ -1245,7 +1232,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { self.r.define(self.r.graph_root, ident, MacroNS, import_binding); } else { self.r.check_reserved_macro_name(ident, res); - self.insert_unused_macro(ident, def_id, item.id, &rule_spans); + self.insert_unused_macro(ident, def_id, item.id); } self.r.visibilities.insert(def_id, vis); let scope = self.r.arenas.alloc_macro_rules_scope(MacroRulesScope::Binding( @@ -1268,7 +1255,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { _ => self.resolve_visibility(&item.vis), }; if !vis.is_public() { - self.insert_unused_macro(ident, def_id, item.id, &rule_spans); + self.insert_unused_macro(ident, def_id, item.id); } self.r.define(module, ident, MacroNS, (res, vis, span, expansion)); self.r.visibilities.insert(def_id, vis); diff --git a/compiler/rustc_resolve/src/def_collector.rs b/compiler/rustc_resolve/src/def_collector.rs index 13df7efe636d..b1ee7f438d29 100644 --- a/compiler/rustc_resolve/src/def_collector.rs +++ b/compiler/rustc_resolve/src/def_collector.rs @@ -111,9 +111,14 @@ impl<'a, 'b, 'tcx> visit::Visitor<'a> for DefCollector<'a, 'b, 'tcx> { return visit::walk_item(self, i); } }; - let def = self.create_def(i.id, def_data, i.span); + let def_id = self.create_def(i.id, def_data, i.span); - self.with_parent(def, |this| { + if let ItemKind::MacroDef(..) = i.kind { + let macro_data = self.resolver.compile_macro(i, self.resolver.tcx.sess.edition()); + self.resolver.macro_map.insert(def_id.to_def_id(), macro_data); + } + + self.with_parent(def_id, |this| { this.with_impl_trait(ImplTraitContext::Existential, |this| { match i.kind { ItemKind::Struct(ref struct_def, _) | ItemKind::Union(ref struct_def, _) => { diff --git a/compiler/rustc_resolve/src/ident.rs b/compiler/rustc_resolve/src/ident.rs index 1a50bd5ec986..a069c6f8e043 100644 --- a/compiler/rustc_resolve/src/ident.rs +++ b/compiler/rustc_resolve/src/ident.rs @@ -240,7 +240,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { { // The macro is a proc macro derive if let Some(def_id) = module.expansion.expn_data().macro_def_id { - let ext = self.get_macro_by_def_id(def_id).ext; + let ext = &self.get_macro_by_def_id(def_id).ext; if ext.builtin_name.is_none() && ext.macro_kind() == MacroKind::Derive && parent.expansion.outer_expn_is_descendant_of(*ctxt) diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 23e8ebc49b0b..29e3697dc706 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -927,9 +927,16 @@ struct DeriveData { #[derive(Clone)] struct MacroData { ext: Lrc, + rule_spans: Vec<(usize, Span)>, macro_rules: bool, } +impl MacroData { + fn new(ext: Lrc) -> MacroData { + MacroData { ext, rule_spans: Vec::new(), macro_rules: false } + } +} + /// The main resolver class. /// /// This is the visitor that walks the whole crate. @@ -1038,7 +1045,7 @@ pub struct Resolver<'a, 'tcx> { macro_map: FxHashMap, dummy_ext_bang: Lrc, dummy_ext_derive: Lrc, - non_macro_attr: Lrc, + non_macro_attr: MacroData, local_macro_def_scopes: FxHashMap>, ast_transform_scopes: FxHashMap>, unused_macros: FxHashMap, @@ -1321,6 +1328,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { let features = tcx.features(); let pub_vis = ty::Visibility::::Public; + let edition = tcx.sess.edition(); let mut resolver = Resolver { tcx, @@ -1402,9 +1410,9 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { registered_tools, macro_use_prelude: FxHashMap::default(), macro_map: FxHashMap::default(), - dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(tcx.sess.edition())), - dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(tcx.sess.edition())), - non_macro_attr: Lrc::new(SyntaxExtension::non_macro_attr(tcx.sess.edition())), + dummy_ext_bang: Lrc::new(SyntaxExtension::dummy_bang(edition)), + dummy_ext_derive: Lrc::new(SyntaxExtension::dummy_derive(edition)), + non_macro_attr: MacroData::new(Lrc::new(SyntaxExtension::non_macro_attr(edition))), invocation_parent_scopes: Default::default(), output_macro_rules_scopes: Default::default(), macro_rules_scopes: Default::default(), @@ -1564,7 +1572,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { match macro_kind { MacroKind::Bang => self.dummy_ext_bang.clone(), MacroKind::Derive => self.dummy_ext_derive.clone(), - MacroKind::Attr => self.non_macro_attr.clone(), + MacroKind::Attr => self.non_macro_attr.ext.clone(), } } diff --git a/compiler/rustc_resolve/src/macros.rs b/compiler/rustc_resolve/src/macros.rs index 7242aa890f82..f8274e7d7d0d 100644 --- a/compiler/rustc_resolve/src/macros.rs +++ b/compiler/rustc_resolve/src/macros.rs @@ -6,7 +6,7 @@ use crate::errors::{ MacroExpectedFound, RemoveSurroundingDerive, }; use crate::Namespace::*; -use crate::{BuiltinMacroState, Determinacy}; +use crate::{BuiltinMacroState, Determinacy, MacroData}; use crate::{DeriveData, Finalize, ParentScope, ResolutionError, Resolver, ScopeSet}; use crate::{ModuleKind, ModuleOrUniformRoot, NameBinding, PathResult, Segment, ToNameBinding}; use rustc_ast::expand::StrippedCfgItem; @@ -695,7 +695,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { res }; - res.map(|res| (self.get_macro(res).map(|macro_data| macro_data.ext), res)) + res.map(|res| (self.get_macro(res).map(|macro_data| macro_data.ext.clone()), res)) } pub(crate) fn finalize_macro_resolutions(&mut self, krate: &Crate) { @@ -936,27 +936,23 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { /// Compile the macro into a `SyntaxExtension` and its rule spans. /// /// Possibly replace its expander to a pre-defined one for built-in macros. - pub(crate) fn compile_macro( - &mut self, - item: &ast::Item, - edition: Edition, - ) -> (SyntaxExtension, Vec<(usize, Span)>) { - let (mut result, mut rule_spans) = + pub(crate) fn compile_macro(&mut self, item: &ast::Item, edition: Edition) -> MacroData { + let (mut ext, mut rule_spans) = compile_declarative_macro(self.tcx.sess, self.tcx.features(), item, edition); - if let Some(builtin_name) = result.builtin_name { + if let Some(builtin_name) = ext.builtin_name { // The macro was marked with `#[rustc_builtin_macro]`. if let Some(builtin_macro) = self.builtin_macros.get_mut(&builtin_name) { // The macro is a built-in, replace its expander function // while still taking everything else from the source code. // If we already loaded this builtin macro, give a better error message than 'no such builtin macro'. match mem::replace(builtin_macro, BuiltinMacroState::AlreadySeen(item.span)) { - BuiltinMacroState::NotYetSeen(ext) => { - result.kind = ext; + BuiltinMacroState::NotYetSeen(builtin_ext) => { + ext.kind = builtin_ext; rule_spans = Vec::new(); if item.id != ast::DUMMY_NODE_ID { self.builtin_macro_kinds - .insert(self.local_def_id(item.id), result.macro_kind()); + .insert(self.local_def_id(item.id), ext.macro_kind()); } } BuiltinMacroState::AlreadySeen(span) => { @@ -976,6 +972,7 @@ impl<'a, 'tcx> Resolver<'a, 'tcx> { } } - (result, rule_spans) + let ItemKind::MacroDef(def) = &item.kind else { unreachable!() }; + MacroData { ext: Lrc::new(ext), rule_spans, macro_rules: def.macro_rules } } } From 2cadd31c042db0530f5a03f37ebcb18cc20562d8 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 30 Oct 2023 21:37:13 +1100 Subject: [PATCH 45/93] coverage: Rename parameter `branching_bcb` to `from_bcb` --- .../rustc_mir_transform/src/coverage/counters.rs | 16 +++++++--------- 1 file changed, 7 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 1e11d8d09b60..f4499433e3fa 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -250,13 +250,12 @@ impl<'a> MakeBcbCounters<'a> { fn make_branch_counters( &mut self, traversal: &TraverseCoverageGraphWithLoops<'_>, - branching_bcb: BasicCoverageBlock, + from_bcb: BasicCoverageBlock, branching_counter_operand: CovTerm, ) { - let branches = self.bcb_branches(branching_bcb); + let branches = self.bcb_branches(from_bcb); debug!( - "{:?} has some branch(es) without counters:\n {}", - branching_bcb, + "{from_bcb:?} has some branch(es) without counters:\n {}", branches .iter() .map(|branch| { format!("{:?}: {:?}", branch, self.branch_counter(branch)) }) @@ -281,14 +280,13 @@ impl<'a> MakeBcbCounters<'a> { if branch != expression_branch { let branch_counter_operand = if branch.is_only_path_to_target() { debug!( - " {:?} has only one incoming edge (from {:?}), so adding a \ - counter", - branch, branching_bcb + " {branch:?} has only one incoming edge (from {from_bcb:?}), \ + so adding a counter", ); self.get_or_make_counter_operand(branch.target_bcb) } else { debug!(" {:?} has multiple incoming edges, so adding an edge counter", branch); - self.get_or_make_edge_counter_operand(branching_bcb, branch.target_bcb) + self.get_or_make_edge_counter_operand(from_bcb, branch.target_bcb) }; if let Some(sumup_counter_operand) = some_sumup_counter_operand.replace(branch_counter_operand) @@ -325,7 +323,7 @@ impl<'a> MakeBcbCounters<'a> { if expression_branch.is_only_path_to_target() { self.coverage_counters.set_bcb_counter(bcb, expression); } else { - self.coverage_counters.set_bcb_edge_counter(branching_bcb, bcb, expression); + self.coverage_counters.set_bcb_edge_counter(from_bcb, bcb, expression); } } From 0a17f0697a726bf714fdeea0366ad364bc030023 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 30 Oct 2023 21:40:08 +1100 Subject: [PATCH 46/93] coverage: Push down and inline `bcb_needs_branch_counters` This lets us avoid creating two copies of the node's branch list. --- .../src/coverage/counters.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index f4499433e3fa..4b0014e502ad 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -228,9 +228,7 @@ impl<'a> MakeBcbCounters<'a> { debug!("{:?} has at least one coverage span. Get or make its counter", bcb); let branching_counter_operand = self.get_or_make_counter_operand(bcb); - if self.bcb_needs_branch_counters(bcb) { - self.make_branch_counters(&traversal, bcb, branching_counter_operand); - } + self.make_branch_counters(&traversal, bcb, branching_counter_operand); } else { debug!( "{:?} does not have any coverage spans. A counter will only be added if \ @@ -254,6 +252,15 @@ impl<'a> MakeBcbCounters<'a> { branching_counter_operand: CovTerm, ) { let branches = self.bcb_branches(from_bcb); + + // If this node doesn't have multiple out-edges, or all of its out-edges + // already have counters, then we don't need to create edge counters. + let needs_branch_counters = + branches.len() > 1 && branches.iter().any(|branch| self.branch_has_no_counter(branch)); + if !needs_branch_counters { + return; + } + debug!( "{from_bcb:?} has some branch(es) without counters:\n {}", branches @@ -510,12 +517,6 @@ impl<'a> MakeBcbCounters<'a> { .collect::>() } - fn bcb_needs_branch_counters(&self, bcb: BasicCoverageBlock) -> bool { - let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch); - let branches = self.bcb_branches(bcb); - branches.len() > 1 && branches.iter().any(branch_needs_a_counter) - } - fn branch_has_no_counter(&self, branch: &BcbBranch) -> bool { self.branch_counter(branch).is_none() } From df23279e1e57d47ee1fc8d40395cefc05eb63674 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 30 Oct 2023 21:42:10 +1100 Subject: [PATCH 47/93] coverage: Push down creation of a visited node's counter Now that this code path unconditionally calls `make_branch_counters`, we might as well make that method responsible for creating the node's counter as well, since it needs the resulting term anyway. --- .../rustc_mir_transform/src/coverage/counters.rs | 13 +++++++------ 1 file changed, 7 insertions(+), 6 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 4b0014e502ad..bb07c2d390c3 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -226,9 +226,7 @@ impl<'a> MakeBcbCounters<'a> { while let Some(bcb) = traversal.next() { if bcb_has_coverage_spans(bcb) { debug!("{:?} has at least one coverage span. Get or make its counter", bcb); - let branching_counter_operand = self.get_or_make_counter_operand(bcb); - - self.make_branch_counters(&traversal, bcb, branching_counter_operand); + self.make_node_and_branch_counters(&traversal, bcb); } else { debug!( "{:?} does not have any coverage spans. A counter will only be added if \ @@ -245,12 +243,15 @@ impl<'a> MakeBcbCounters<'a> { ); } - fn make_branch_counters( + fn make_node_and_branch_counters( &mut self, traversal: &TraverseCoverageGraphWithLoops<'_>, from_bcb: BasicCoverageBlock, - branching_counter_operand: CovTerm, ) { + // First, ensure that this node has a counter of some kind. + // We might also use its term later to compute one of the branch counters. + let from_bcb_operand = self.get_or_make_counter_operand(from_bcb); + let branches = self.bcb_branches(from_bcb); // If this node doesn't have multiple out-edges, or all of its out-edges @@ -321,7 +322,7 @@ impl<'a> MakeBcbCounters<'a> { self.bcb_predecessors(expression_branch.target_bcb), ); let expression = self.coverage_counters.make_expression( - branching_counter_operand, + from_bcb_operand, Op::Subtract, sumup_counter_operand, ); From 31113c5f56fa372760552de68a87ca67bdbeb1f6 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 1 Nov 2023 11:23:27 +1100 Subject: [PATCH 48/93] coverage: Use `BcbCounter` to build coverage expressions This means that we no longer have to manage the distinction between `BcbCounter` and `CovTerm` when preparing expressions. --- .../src/coverage/counters.rs | 35 +++++++++---------- 1 file changed, 16 insertions(+), 19 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index bb07c2d390c3..e96c7c84d88b 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -12,7 +12,7 @@ use std::fmt::{self, Debug}; /// The coverage counter or counter expression associated with a particular /// BCB node or BCB edge. -#[derive(Clone)] +#[derive(Clone, Copy)] pub(super) enum BcbCounter { Counter { id: CounterId }, Expression { id: ExpressionId }, @@ -88,8 +88,9 @@ impl CoverageCounters { BcbCounter::Counter { id } } - fn make_expression(&mut self, lhs: CovTerm, op: Op, rhs: CovTerm) -> BcbCounter { - let id = self.expressions.push(Expression { lhs, op, rhs }); + fn make_expression(&mut self, lhs: BcbCounter, op: Op, rhs: BcbCounter) -> BcbCounter { + let expression = Expression { lhs: lhs.as_term(), op, rhs: rhs.as_term() }; + let id = self.expressions.push(expression); BcbCounter::Expression { id } } @@ -109,7 +110,7 @@ impl CoverageCounters { self.expressions.len() } - fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> CovTerm { + fn set_bcb_counter(&mut self, bcb: BasicCoverageBlock, counter_kind: BcbCounter) -> BcbCounter { assert!( // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also // have an expression (to be injected into an existing `BasicBlock` represented by this @@ -118,14 +119,13 @@ impl CoverageCounters { "attempt to add a `Counter` to a BCB target with existing incoming edge counters" ); - let term = counter_kind.as_term(); if let Some(replaced) = self.bcb_counters[bcb].replace(counter_kind) { bug!( "attempt to set a BasicCoverageBlock coverage counter more than once; \ {bcb:?} already had counter {replaced:?}", ); } else { - term + counter_kind } } @@ -134,7 +134,7 @@ impl CoverageCounters { from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, counter_kind: BcbCounter, - ) -> CovTerm { + ) -> BcbCounter { // If the BCB has an edge counter (to be injected into a new `BasicBlock`), it can also // have an expression (to be injected into an existing `BasicBlock` represented by this // `BasicCoverageBlock`). @@ -148,14 +148,13 @@ impl CoverageCounters { } self.bcb_has_incoming_edge_counters.insert(to_bcb); - let term = counter_kind.as_term(); if let Some(replaced) = self.bcb_edge_counters.insert((from_bcb, to_bcb), counter_kind) { bug!( "attempt to set an edge counter more than once; from_bcb: \ {from_bcb:?} already had counter {replaced:?}", ); } else { - term + counter_kind } } @@ -305,8 +304,7 @@ impl<'a> MakeBcbCounters<'a> { sumup_counter_operand, ); debug!(" [new intermediate expression: {:?}]", intermediate_expression); - let intermediate_expression_operand = intermediate_expression.as_term(); - some_sumup_counter_operand.replace(intermediate_expression_operand); + some_sumup_counter_operand.replace(intermediate_expression); } } } @@ -336,11 +334,11 @@ impl<'a> MakeBcbCounters<'a> { } #[instrument(level = "debug", skip(self))] - fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> CovTerm { + fn get_or_make_counter_operand(&mut self, bcb: BasicCoverageBlock) -> BcbCounter { // If the BCB already has a counter, return it. - if let Some(counter_kind) = &self.coverage_counters.bcb_counters[bcb] { + if let Some(counter_kind) = self.coverage_counters.bcb_counters[bcb] { debug!("{bcb:?} already has a counter: {counter_kind:?}"); - return counter_kind.as_term(); + return counter_kind; } // A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`). @@ -382,8 +380,7 @@ impl<'a> MakeBcbCounters<'a> { edge_counter_operand, ); debug!("new intermediate expression: {intermediate_expression:?}"); - let intermediate_expression_operand = intermediate_expression.as_term(); - some_sumup_edge_counter_operand.replace(intermediate_expression_operand); + some_sumup_edge_counter_operand.replace(intermediate_expression); } } let counter_kind = self.coverage_counters.make_expression( @@ -402,7 +399,7 @@ impl<'a> MakeBcbCounters<'a> { &mut self, from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, - ) -> CovTerm { + ) -> BcbCounter { // If the source BCB has only one successor (assumed to be the given target), an edge // counter is unnecessary. Just get or make a counter for the source BCB. let successors = self.bcb_successors(from_bcb).iter(); @@ -411,11 +408,11 @@ impl<'a> MakeBcbCounters<'a> { } // If the edge already has a counter, return it. - if let Some(counter_kind) = + if let Some(&counter_kind) = self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)) { debug!("Edge {from_bcb:?}->{to_bcb:?} already has a counter: {counter_kind:?}"); - return counter_kind.as_term(); + return counter_kind; } // Make a new counter to count this edge. From a1e2c10b1fe2e43a4565d3ac0013a2b72f430aa9 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Tue, 31 Oct 2023 17:44:26 +1100 Subject: [PATCH 49/93] coverage: Simplify building coverage expressions based on sums In some cases we need to prepare a coverage expression that is the sum of an arbitrary number of other terms. This patch simplifies the code paths that build those sums. This causes some churn in the mappings, because the previous code was building its sums in a somewhat idiosyncratic order. --- .../src/coverage/counters.rs | 121 ++++++++---------- tests/coverage/async.cov-map | 28 ++-- tests/coverage/conditions.cov-map | 10 +- tests/coverage/continue.cov-map | 46 +++---- tests/coverage/coroutine.cov-map | 8 +- tests/coverage/loops_branches.cov-map | 90 ++++++------- tests/coverage/try_error_result.cov-map | 18 +-- 7 files changed, 152 insertions(+), 169 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index e96c7c84d88b..ca7feb942fe5 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -94,6 +94,14 @@ impl CoverageCounters { BcbCounter::Expression { id } } + /// Variant of `make_expression` that makes `lhs` optional and assumes [`Op::Add`]. + /// + /// This is useful when using [`Iterator::fold`] to build an arbitrary-length sum. + fn make_sum_expression(&mut self, lhs: Option, rhs: BcbCounter) -> BcbCounter { + let Some(lhs) = lhs else { return rhs }; + self.make_expression(lhs, Op::Add, rhs) + } + /// Counter IDs start from one and go up. fn next_counter(&mut self) -> CounterId { let next = self.next_counter_id; @@ -158,8 +166,8 @@ impl CoverageCounters { } } - pub(super) fn bcb_counter(&self, bcb: BasicCoverageBlock) -> Option<&BcbCounter> { - self.bcb_counters[bcb].as_ref() + pub(super) fn bcb_counter(&self, bcb: BasicCoverageBlock) -> Option { + self.bcb_counters[bcb] } pub(super) fn bcb_node_counters( @@ -278,41 +286,30 @@ impl<'a> MakeBcbCounters<'a> { // counter.) let expression_branch = self.choose_preferred_expression_branch(traversal, &branches); - // Assign a Counter or Expression to each branch, plus additional `Expression`s, as needed, - // to sum up intermediate results. - let mut some_sumup_counter_operand = None; - for branch in branches { - // Skip the selected `expression_branch`, if any. It's expression will be assigned after - // all others. - if branch != expression_branch { - let branch_counter_operand = if branch.is_only_path_to_target() { - debug!( - " {branch:?} has only one incoming edge (from {from_bcb:?}), \ - so adding a counter", - ); - self.get_or_make_counter_operand(branch.target_bcb) - } else { - debug!(" {:?} has multiple incoming edges, so adding an edge counter", branch); - self.get_or_make_edge_counter_operand(from_bcb, branch.target_bcb) - }; - if let Some(sumup_counter_operand) = - some_sumup_counter_operand.replace(branch_counter_operand) - { - let intermediate_expression = self.coverage_counters.make_expression( - branch_counter_operand, - Op::Add, - sumup_counter_operand, - ); - debug!(" [new intermediate expression: {:?}]", intermediate_expression); - some_sumup_counter_operand.replace(intermediate_expression); - } - } - } + // For each branch arm other than the one that was chosen to get an expression, + // ensure that it has a counter (existing counter/expression or a new counter), + // and accumulate the corresponding terms into a single sum term. + let sum_of_all_other_branches: BcbCounter = { + let _span = debug_span!("sum_of_all_other_branches", ?expression_branch).entered(); + branches + .into_iter() + // Skip the chosen branch, since we'll calculate it from the other branches. + .filter(|branch| branch != &expression_branch) + .fold(None, |accum, branch| { + let _span = debug_span!("branch", ?accum, ?branch).entered(); + let branch_counter = if branch.is_only_path_to_target() { + self.get_or_make_counter_operand(branch.target_bcb) + } else { + self.get_or_make_edge_counter_operand(from_bcb, branch.target_bcb) + }; + Some(self.coverage_counters.make_sum_expression(accum, branch_counter)) + }) + .expect("there must be at least one other branch") + }; - // Assign the final expression to the `expression_branch` by subtracting the total of all - // other branches from the counter of the branching BCB. - let sumup_counter_operand = - some_sumup_counter_operand.expect("sumup_counter_operand should have a value"); + // For the branch that was chosen to get an expression, create that expression + // by taking the count of the node we're branching from, and subtracting the + // sum of all the other branches. debug!( "Making an expression for the selected expression_branch: {:?} \ (expression_branch predecessors: {:?})", @@ -322,7 +319,7 @@ impl<'a> MakeBcbCounters<'a> { let expression = self.coverage_counters.make_expression( from_bcb_operand, Op::Subtract, - sumup_counter_operand, + sum_of_all_other_branches, ); debug!("{:?} gets an expression: {:?}", expression_branch, expression); let bcb = expression_branch.target_bcb; @@ -359,39 +356,25 @@ impl<'a> MakeBcbCounters<'a> { return self.coverage_counters.set_bcb_counter(bcb, counter_kind); } - // A BCB with multiple incoming edges can compute its count by `Expression`, summing up the - // counters and/or expressions of its incoming edges. This will recursively get or create - // counters for those incoming edges first, then call `make_expression()` to sum them up, - // with additional intermediate expressions as needed. - let _sumup_debug_span = debug_span!("(preparing sum-up expression)").entered(); + // A BCB with multiple incoming edges can compute its count by ensuring that counters + // exist for each of those edges, and then adding them up to get a total count. + let sum_of_in_edges: BcbCounter = { + let _span = debug_span!("sum_of_in_edges", ?bcb).entered(); + // We avoid calling `self.bcb_predecessors` here so that we can + // call methods on `&mut self` inside the fold. + self.basic_coverage_blocks.predecessors[bcb] + .iter() + .copied() + .fold(None, |accum, from_bcb| { + let _span = debug_span!("from_bcb", ?accum, ?from_bcb).entered(); + let edge_counter = self.get_or_make_edge_counter_operand(from_bcb, bcb); + Some(self.coverage_counters.make_sum_expression(accum, edge_counter)) + }) + .expect("there must be at least one in-edge") + }; - let mut predecessors = self.bcb_predecessors(bcb).to_owned().into_iter(); - let first_edge_counter_operand = - self.get_or_make_edge_counter_operand(predecessors.next().unwrap(), bcb); - let mut some_sumup_edge_counter_operand = None; - for predecessor in predecessors { - let edge_counter_operand = self.get_or_make_edge_counter_operand(predecessor, bcb); - if let Some(sumup_edge_counter_operand) = - some_sumup_edge_counter_operand.replace(edge_counter_operand) - { - let intermediate_expression = self.coverage_counters.make_expression( - sumup_edge_counter_operand, - Op::Add, - edge_counter_operand, - ); - debug!("new intermediate expression: {intermediate_expression:?}"); - some_sumup_edge_counter_operand.replace(intermediate_expression); - } - } - let counter_kind = self.coverage_counters.make_expression( - first_edge_counter_operand, - Op::Add, - some_sumup_edge_counter_operand.unwrap(), - ); - drop(_sumup_debug_span); - - debug!("{bcb:?} gets a new counter (sum of predecessor counters): {counter_kind:?}"); - self.coverage_counters.set_bcb_counter(bcb, counter_kind) + debug!("{bcb:?} gets a new counter (sum of predecessor counters): {sum_of_in_edges:?}"); + self.coverage_counters.set_bcb_counter(bcb, sum_of_in_edges) } #[instrument(level = "debug", skip(self))] diff --git a/tests/coverage/async.cov-map b/tests/coverage/async.cov-map index 598791537ad6..857e0a536a70 100644 --- a/tests/coverage/async.cov-map +++ b/tests/coverage/async.cov-map @@ -197,12 +197,12 @@ Number of file 0 mappings: 1 - Code(Counter(0)) at (prev + 38, 1) to (start + 0, 19) Function name: async::i::{closure#0} -Raw bytes (78): 0x[01, 01, 02, 19, 07, 1d, 21, 0e, 01, 26, 13, 04, 0c, 0d, 05, 09, 00, 0a, 01, 00, 0e, 00, 12, 05, 00, 13, 00, 18, 09, 00, 1c, 00, 21, 0d, 00, 27, 00, 2a, 15, 00, 2b, 00, 30, 1d, 01, 09, 00, 0a, 11, 00, 0e, 00, 11, 25, 00, 12, 00, 17, 29, 00, 1b, 00, 20, 1d, 00, 24, 00, 26, 21, 01, 0e, 00, 10, 03, 02, 01, 00, 02] +Raw bytes (78): 0x[01, 01, 02, 07, 21, 19, 1d, 0e, 01, 26, 13, 04, 0c, 0d, 05, 09, 00, 0a, 01, 00, 0e, 00, 12, 05, 00, 13, 00, 18, 09, 00, 1c, 00, 21, 0d, 00, 27, 00, 2a, 15, 00, 2b, 00, 30, 1d, 01, 09, 00, 0a, 11, 00, 0e, 00, 11, 25, 00, 12, 00, 17, 29, 00, 1b, 00, 20, 1d, 00, 24, 00, 26, 21, 01, 0e, 00, 10, 03, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 -- expression 0 operands: lhs = Counter(6), rhs = Expression(1, Add) -- expression 1 operands: lhs = Counter(7), rhs = Counter(8) +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(8) +- expression 1 operands: lhs = Counter(6), rhs = Counter(7) Number of file 0 mappings: 14 - Code(Counter(0)) at (prev + 38, 19) to (start + 4, 12) - Code(Counter(3)) at (prev + 5, 9) to (start + 0, 10) @@ -218,15 +218,15 @@ Number of file 0 mappings: 14 - Code(Counter(7)) at (prev + 0, 36) to (start + 0, 38) - Code(Counter(8)) at (prev + 1, 14) to (start + 0, 16) - Code(Expression(0, Add)) at (prev + 2, 1) to (start + 0, 2) - = (c6 + (c7 + c8)) + = ((c6 + c7) + c8) Function name: async::j -Raw bytes (53): 0x[01, 01, 02, 05, 07, 09, 0d, 09, 01, 31, 01, 13, 0c, 05, 14, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 11, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 0d, 01, 0e, 00, 10, 03, 02, 01, 00, 02] +Raw bytes (53): 0x[01, 01, 02, 07, 0d, 05, 09, 09, 01, 31, 01, 13, 0c, 05, 14, 09, 00, 0a, 01, 00, 0e, 00, 1b, 05, 00, 1f, 00, 27, 09, 01, 09, 00, 0a, 11, 00, 0e, 00, 1a, 09, 00, 1e, 00, 20, 0d, 01, 0e, 00, 10, 03, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 2 -- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Add) -- expression 1 operands: lhs = Counter(2), rhs = Counter(3) +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 49, 1) to (start + 19, 12) - Code(Counter(1)) at (prev + 20, 9) to (start + 0, 10) @@ -237,7 +237,7 @@ Number of file 0 mappings: 9 - Code(Counter(2)) at (prev + 0, 30) to (start + 0, 32) - Code(Counter(3)) at (prev + 1, 14) to (start + 0, 16) - Code(Expression(0, Add)) at (prev + 2, 1) to (start + 0, 2) - = (c1 + (c2 + c3)) + = ((c1 + c2) + c3) Function name: async::j::c Raw bytes (28): 0x[01, 01, 02, 01, 05, 05, 02, 04, 01, 33, 05, 01, 12, 05, 02, 0d, 00, 0e, 02, 0a, 0d, 00, 0e, 07, 02, 05, 00, 06] @@ -283,22 +283,22 @@ Number of file 0 mappings: 5 - Code(Zero) at (prev + 2, 1) to (start + 0, 2) Function name: async::l -Raw bytes (37): 0x[01, 01, 04, 01, 07, 09, 05, 09, 0f, 05, 02, 05, 01, 53, 01, 01, 0c, 02, 02, 0e, 00, 10, 05, 01, 0e, 00, 10, 09, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] +Raw bytes (37): 0x[01, 01, 04, 01, 07, 05, 09, 0f, 02, 09, 05, 05, 01, 53, 01, 01, 0c, 02, 02, 0e, 00, 10, 05, 01, 0e, 00, 10, 09, 01, 0e, 00, 10, 0b, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 4 - expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) -- expression 1 operands: lhs = Counter(2), rhs = Counter(1) -- expression 2 operands: lhs = Counter(2), rhs = Expression(3, Add) -- expression 3 operands: lhs = Counter(1), rhs = Expression(0, Sub) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 2 operands: lhs = Expression(3, Add), rhs = Expression(0, Sub) +- expression 3 operands: lhs = Counter(2), rhs = Counter(1) Number of file 0 mappings: 5 - Code(Counter(0)) at (prev + 83, 1) to (start + 1, 12) - Code(Expression(0, Sub)) at (prev + 2, 14) to (start + 0, 16) - = (c0 - (c2 + c1)) + = (c0 - (c1 + c2)) - Code(Counter(1)) at (prev + 1, 14) to (start + 0, 16) - Code(Counter(2)) at (prev + 1, 14) to (start + 0, 16) - Code(Expression(2, Add)) at (prev + 2, 1) to (start + 0, 2) - = (c2 + (c1 + (c0 - (c2 + c1)))) + = ((c2 + c1) + (c0 - (c1 + c2))) Function name: async::m Raw bytes (9): 0x[01, 01, 00, 01, 01, 5b, 01, 00, 19] diff --git a/tests/coverage/conditions.cov-map b/tests/coverage/conditions.cov-map index 7600d2d96bdf..cfee55ed31a4 100644 --- a/tests/coverage/conditions.cov-map +++ b/tests/coverage/conditions.cov-map @@ -1,5 +1,5 @@ Function name: conditions::main -Raw bytes (784): 0x[01, 01, 8e, 01, 09, 33, 37, 41, 3b, 3d, 35, 39, 05, 00, b7, 04, 09, 05, 00, 0d, 35, 26, 39, 0d, 35, 3b, 3d, 35, 39, 37, 41, 3b, 3d, 35, 39, b2, 04, 0d, b7, 04, 09, 05, 00, 45, 00, 83, 01, 49, 45, 00, 7e, 31, 83, 01, 49, 45, 00, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, 76, 51, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, a7, 01, 55, 4d, 51, a3, 01, 59, a7, 01, 55, 4d, 51, 49, 9f, 01, a3, 01, 59, a7, 01, 55, 4d, 51, 61, 00, e3, 01, 65, 61, 00, de, 01, 2d, e3, 01, 65, 61, 00, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, d6, 01, 6d, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, 8b, 02, 71, 69, 6d, 87, 02, 75, 8b, 02, 71, 69, 6d, ff, 01, 00, 65, 83, 02, 87, 02, 75, 8b, 02, 71, 69, 6d, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 79, 00, d7, 02, 7d, 79, 00, d2, 02, 29, d7, 02, 7d, 79, 00, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, ca, 02, 85, 01, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, f3, 03, 89, 01, 81, 01, 85, 01, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, da, 03, 19, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 9b, 04, 1d, 15, 19, 97, 04, 21, 9b, 04, 1d, 15, 19, 8f, 04, 9f, 04, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, a3, 04, ae, 04, a7, 04, ab, 04, 25, 29, 2d, 31, b2, 04, 0d, b7, 04, 09, 05, 00, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, b7, 04, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, b2, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 26, 00, 1d, 00, 2a, 22, 00, 2e, 00, 3c, 37, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 33, 01, 09, 01, 12, ae, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 83, 01, 02, 08, 00, 15, 49, 00, 16, 02, 06, 7e, 02, 0f, 00, 1c, 7a, 01, 0c, 00, 19, 76, 00, 1d, 00, 2a, 72, 00, 2e, 00, 3c, a3, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, 9f, 01, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 9b, 01, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, e3, 01, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, de, 01, 03, 11, 00, 1e, da, 01, 01, 10, 00, 1d, d6, 01, 00, 21, 00, 2e, d2, 01, 00, 32, 00, 40, 87, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, 83, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, fb, 01, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, e7, 03, 02, 09, 00, 0a, d7, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, d2, 02, 02, 0f, 00, 1c, ce, 02, 01, 0c, 00, 19, ca, 02, 00, 1d, 00, 2a, c6, 02, 00, 2e, 00, 3c, ef, 03, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, eb, 03, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, 8f, 04, 05, 09, 00, 0a, e7, 03, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, e2, 03, 02, 0f, 00, 1c, de, 03, 01, 0c, 00, 19, da, 03, 00, 1d, 00, 2a, d6, 03, 00, 2e, 00, 3c, 97, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, 93, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, 8b, 04, 02, 01, 00, 02] +Raw bytes (784): 0x[01, 01, 8e, 01, 09, 33, 37, 41, 3b, 3d, 35, 39, 05, 00, b7, 04, 09, 05, 00, 0d, 35, 26, 39, 0d, 35, 3b, 3d, 35, 39, 37, 41, 3b, 3d, 35, 39, b2, 04, 0d, b7, 04, 09, 05, 00, 45, 00, 83, 01, 49, 45, 00, 7e, 31, 83, 01, 49, 45, 00, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, 76, 51, 7a, 4d, 7e, 31, 83, 01, 49, 45, 00, a7, 01, 55, 4d, 51, a3, 01, 59, a7, 01, 55, 4d, 51, 49, 9f, 01, a3, 01, 59, a7, 01, 55, 4d, 51, 61, 00, e3, 01, 65, 61, 00, de, 01, 2d, e3, 01, 65, 61, 00, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, d6, 01, 6d, da, 01, 69, de, 01, 2d, e3, 01, 65, 61, 00, 8b, 02, 71, 69, 6d, 87, 02, 75, 8b, 02, 71, 69, 6d, ff, 01, 00, 65, 83, 02, 87, 02, 75, 8b, 02, 71, 69, 6d, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 79, 00, d7, 02, 7d, 79, 00, d2, 02, 29, d7, 02, 7d, 79, 00, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, ca, 02, 85, 01, ce, 02, 81, 01, d2, 02, 29, d7, 02, 7d, 79, 00, f3, 03, 89, 01, 81, 01, 85, 01, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, da, 03, 19, de, 03, 15, e2, 03, 25, e7, 03, 11, 7d, eb, 03, ef, 03, 8d, 01, f3, 03, 89, 01, 81, 01, 85, 01, 9b, 04, 1d, 15, 19, 97, 04, 21, 9b, 04, 1d, 15, 19, 8f, 04, 9f, 04, 11, 93, 04, 97, 04, 21, 9b, 04, 1d, 15, 19, a3, 04, ae, 04, a7, 04, 31, ab, 04, 2d, 25, 29, b2, 04, 0d, b7, 04, 09, 05, 00, 44, 01, 03, 01, 02, 0c, 05, 02, 0d, 02, 06, 00, 02, 06, 00, 07, 03, 03, 09, 00, 0a, b7, 04, 00, 10, 00, 1d, 09, 01, 09, 01, 0a, b2, 04, 02, 0f, 00, 1c, 0d, 01, 0c, 00, 19, 26, 00, 1d, 00, 2a, 22, 00, 2e, 00, 3c, 37, 00, 3d, 02, 0a, 41, 02, 0a, 00, 0b, 33, 01, 09, 01, 12, ae, 04, 03, 09, 00, 0f, 03, 03, 09, 01, 0c, 45, 01, 0d, 02, 06, 00, 02, 06, 00, 07, 83, 01, 02, 08, 00, 15, 49, 00, 16, 02, 06, 7e, 02, 0f, 00, 1c, 7a, 01, 0c, 00, 19, 76, 00, 1d, 00, 2a, 72, 00, 2e, 00, 3c, a3, 01, 00, 3d, 02, 0a, 59, 02, 0a, 00, 0b, 9f, 01, 01, 09, 00, 17, 31, 02, 09, 00, 0f, 9b, 01, 03, 08, 00, 0c, 5d, 01, 0d, 01, 10, 61, 01, 11, 02, 0a, 00, 02, 0a, 00, 0b, e3, 01, 02, 0c, 00, 19, 65, 00, 1a, 02, 0a, de, 01, 03, 11, 00, 1e, da, 01, 01, 10, 00, 1d, d6, 01, 00, 21, 00, 2e, d2, 01, 00, 32, 00, 40, 87, 02, 00, 41, 02, 0e, 75, 02, 0e, 00, 0f, 83, 02, 01, 0d, 00, 1b, 2d, 02, 0d, 00, 13, 00, 02, 06, 00, 07, fb, 01, 02, 09, 01, 0c, 79, 01, 0d, 02, 06, 00, 02, 06, 00, 07, e7, 03, 02, 09, 00, 0a, d7, 02, 00, 10, 00, 1d, 7d, 00, 1e, 02, 06, d2, 02, 02, 0f, 00, 1c, ce, 02, 01, 0c, 00, 19, ca, 02, 00, 1d, 00, 2a, c6, 02, 00, 2e, 00, 3c, ef, 03, 00, 3d, 02, 0a, 8d, 01, 02, 0a, 00, 0b, eb, 03, 01, 09, 00, 17, 29, 02, 0d, 02, 0f, 8f, 04, 05, 09, 00, 0a, e7, 03, 00, 10, 00, 1d, 11, 00, 1e, 02, 06, e2, 03, 02, 0f, 00, 1c, de, 03, 01, 0c, 00, 19, da, 03, 00, 1d, 00, 2a, d6, 03, 00, 2e, 00, 3c, 97, 04, 00, 3d, 02, 0a, 21, 02, 0a, 00, 0b, 93, 04, 01, 09, 00, 17, 25, 02, 09, 00, 0f, 8b, 04, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 142 @@ -139,9 +139,9 @@ Number of expressions: 142 - expression 133 operands: lhs = Expression(134, Add), rhs = Counter(7) - expression 134 operands: lhs = Counter(5), rhs = Counter(6) - expression 135 operands: lhs = Expression(136, Add), rhs = Expression(139, Sub) -- expression 136 operands: lhs = Expression(137, Add), rhs = Expression(138, Add) -- expression 137 operands: lhs = Counter(9), rhs = Counter(10) -- expression 138 operands: lhs = Counter(11), rhs = Counter(12) +- expression 136 operands: lhs = Expression(137, Add), rhs = Counter(12) +- expression 137 operands: lhs = Expression(138, Add), rhs = Counter(11) +- expression 138 operands: lhs = Counter(9), rhs = Counter(10) - expression 139 operands: lhs = Expression(140, Sub), rhs = Counter(3) - expression 140 operands: lhs = Expression(141, Add), rhs = Counter(2) - expression 141 operands: lhs = Counter(1), rhs = Zero @@ -255,5 +255,5 @@ Number of file 0 mappings: 68 = (((c5 + c6) + c7) + c8) - Code(Counter(9)) at (prev + 2, 9) to (start + 0, 15) - Code(Expression(130, Add)) at (prev + 2, 1) to (start + 0, 2) - = ((c4 + (((c5 + c6) + c7) + c8)) + (((c9 + c10) + (c11 + c12)) + (((c1 + Zero) - c2) - c3))) + = ((c4 + (((c5 + c6) + c7) + c8)) + ((((c9 + c10) + c11) + c12) + (((c1 + Zero) - c2) - c3))) diff --git a/tests/coverage/continue.cov-map b/tests/coverage/continue.cov-map index 82f3d7c60952..810694d7f662 100644 --- a/tests/coverage/continue.cov-map +++ b/tests/coverage/continue.cov-map @@ -1,26 +1,26 @@ Function name: continue::main -Raw bytes (210): 0x[01, 01, 1c, 01, 07, 05, 09, 03, 0d, 0d, 1f, 11, 15, 1b, 19, 0d, 1f, 11, 15, 19, 33, 1d, 21, 2f, 25, 19, 33, 1d, 21, 25, 47, 29, 2d, 43, 31, 25, 47, 29, 2d, 31, 5f, 35, 39, 57, 3d, 31, 5f, 35, 39, 35, 39, 3d, 41, 6b, 45, 3d, 41, 49, 45, 1e, 01, 03, 01, 03, 12, 03, 04, 0e, 00, 13, 0a, 01, 0f, 00, 16, 05, 02, 11, 00, 19, 09, 02, 12, 04, 0e, 1b, 06, 0e, 00, 13, 16, 01, 0f, 00, 16, 15, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 15, 03, 09, 00, 0e, 2f, 02, 0e, 00, 13, 2a, 01, 0f, 00, 16, 1d, 01, 15, 02, 0e, 21, 04, 11, 00, 19, 1d, 03, 09, 00, 0e, 43, 02, 0e, 00, 13, 3e, 01, 0c, 00, 13, 29, 01, 0d, 00, 15, 2d, 01, 0a, 01, 0e, 57, 03, 0e, 00, 13, 52, 01, 0f, 00, 16, 39, 01, 16, 02, 0e, 35, 03, 12, 02, 0e, 5f, 04, 09, 00, 0e, 6b, 02, 0e, 00, 13, 66, 01, 0f, 00, 16, 41, 01, 16, 02, 0e, 49, 04, 11, 00, 16, 41, 03, 09, 00, 0e, 6f, 02, 0d, 01, 02] +Raw bytes (210): 0x[01, 01, 1c, 07, 09, 01, 05, 03, 0d, 1f, 15, 0d, 11, 1b, 19, 1f, 15, 0d, 11, 33, 21, 19, 1d, 2f, 25, 33, 21, 19, 1d, 47, 2d, 25, 29, 43, 31, 47, 2d, 25, 29, 31, 5f, 35, 39, 57, 3d, 31, 5f, 35, 39, 35, 39, 3d, 41, 6b, 45, 3d, 41, 49, 45, 1e, 01, 03, 01, 03, 12, 03, 04, 0e, 00, 13, 0a, 01, 0f, 00, 16, 05, 02, 11, 00, 19, 09, 02, 12, 04, 0e, 1b, 06, 0e, 00, 13, 16, 01, 0f, 00, 16, 15, 01, 16, 02, 0e, 11, 04, 11, 00, 19, 15, 03, 09, 00, 0e, 2f, 02, 0e, 00, 13, 2a, 01, 0f, 00, 16, 1d, 01, 15, 02, 0e, 21, 04, 11, 00, 19, 1d, 03, 09, 00, 0e, 43, 02, 0e, 00, 13, 3e, 01, 0c, 00, 13, 29, 01, 0d, 00, 15, 2d, 01, 0a, 01, 0e, 57, 03, 0e, 00, 13, 52, 01, 0f, 00, 16, 39, 01, 16, 02, 0e, 35, 03, 12, 02, 0e, 5f, 04, 09, 00, 0e, 6b, 02, 0e, 00, 13, 66, 01, 0f, 00, 16, 41, 01, 16, 02, 0e, 49, 04, 11, 00, 16, 41, 03, 09, 00, 0e, 6f, 02, 0d, 01, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 28 -- expression 0 operands: lhs = Counter(0), rhs = Expression(1, Add) -- expression 1 operands: lhs = Counter(1), rhs = Counter(2) +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(2) +- expression 1 operands: lhs = Counter(0), rhs = Counter(1) - expression 2 operands: lhs = Expression(0, Add), rhs = Counter(3) -- expression 3 operands: lhs = Counter(3), rhs = Expression(7, Add) -- expression 4 operands: lhs = Counter(4), rhs = Counter(5) +- expression 3 operands: lhs = Expression(7, Add), rhs = Counter(5) +- expression 4 operands: lhs = Counter(3), rhs = Counter(4) - expression 5 operands: lhs = Expression(6, Add), rhs = Counter(6) -- expression 6 operands: lhs = Counter(3), rhs = Expression(7, Add) -- expression 7 operands: lhs = Counter(4), rhs = Counter(5) -- expression 8 operands: lhs = Counter(6), rhs = Expression(12, Add) -- expression 9 operands: lhs = Counter(7), rhs = Counter(8) +- expression 6 operands: lhs = Expression(7, Add), rhs = Counter(5) +- expression 7 operands: lhs = Counter(3), rhs = Counter(4) +- expression 8 operands: lhs = Expression(12, Add), rhs = Counter(8) +- expression 9 operands: lhs = Counter(6), rhs = Counter(7) - expression 10 operands: lhs = Expression(11, Add), rhs = Counter(9) -- expression 11 operands: lhs = Counter(6), rhs = Expression(12, Add) -- expression 12 operands: lhs = Counter(7), rhs = Counter(8) -- expression 13 operands: lhs = Counter(9), rhs = Expression(17, Add) -- expression 14 operands: lhs = Counter(10), rhs = Counter(11) +- expression 11 operands: lhs = Expression(12, Add), rhs = Counter(8) +- expression 12 operands: lhs = Counter(6), rhs = Counter(7) +- expression 13 operands: lhs = Expression(17, Add), rhs = Counter(11) +- expression 14 operands: lhs = Counter(9), rhs = Counter(10) - expression 15 operands: lhs = Expression(16, Add), rhs = Counter(12) -- expression 16 operands: lhs = Counter(9), rhs = Expression(17, Add) -- expression 17 operands: lhs = Counter(10), rhs = Counter(11) +- expression 16 operands: lhs = Expression(17, Add), rhs = Counter(11) +- expression 17 operands: lhs = Counter(9), rhs = Counter(10) - expression 18 operands: lhs = Counter(12), rhs = Expression(23, Add) - expression 19 operands: lhs = Counter(13), rhs = Counter(14) - expression 20 operands: lhs = Expression(21, Add), rhs = Counter(15) @@ -34,29 +34,29 @@ Number of expressions: 28 Number of file 0 mappings: 30 - Code(Counter(0)) at (prev + 3, 1) to (start + 3, 18) - Code(Expression(0, Add)) at (prev + 4, 14) to (start + 0, 19) - = (c0 + (c1 + c2)) + = ((c0 + c1) + c2) - Code(Expression(2, Sub)) at (prev + 1, 15) to (start + 0, 22) - = ((c0 + (c1 + c2)) - c3) + = (((c0 + c1) + c2) - c3) - Code(Counter(1)) at (prev + 2, 17) to (start + 0, 25) - Code(Counter(2)) at (prev + 2, 18) to (start + 4, 14) - Code(Expression(6, Add)) at (prev + 6, 14) to (start + 0, 19) - = (c3 + (c4 + c5)) + = ((c3 + c4) + c5) - Code(Expression(5, Sub)) at (prev + 1, 15) to (start + 0, 22) - = ((c3 + (c4 + c5)) - c6) + = (((c3 + c4) + c5) - c6) - Code(Counter(5)) at (prev + 1, 22) to (start + 2, 14) - Code(Counter(4)) at (prev + 4, 17) to (start + 0, 25) - Code(Counter(5)) at (prev + 3, 9) to (start + 0, 14) - Code(Expression(11, Add)) at (prev + 2, 14) to (start + 0, 19) - = (c6 + (c7 + c8)) + = ((c6 + c7) + c8) - Code(Expression(10, Sub)) at (prev + 1, 15) to (start + 0, 22) - = ((c6 + (c7 + c8)) - c9) + = (((c6 + c7) + c8) - c9) - Code(Counter(7)) at (prev + 1, 21) to (start + 2, 14) - Code(Counter(8)) at (prev + 4, 17) to (start + 0, 25) - Code(Counter(7)) at (prev + 3, 9) to (start + 0, 14) - Code(Expression(16, Add)) at (prev + 2, 14) to (start + 0, 19) - = (c9 + (c10 + c11)) + = ((c9 + c10) + c11) - Code(Expression(15, Sub)) at (prev + 1, 12) to (start + 0, 19) - = ((c9 + (c10 + c11)) - c12) + = (((c9 + c10) + c11) - c12) - Code(Counter(10)) at (prev + 1, 13) to (start + 0, 21) - Code(Counter(11)) at (prev + 1, 10) to (start + 1, 14) - Code(Expression(21, Add)) at (prev + 3, 14) to (start + 0, 19) diff --git a/tests/coverage/coroutine.cov-map b/tests/coverage/coroutine.cov-map index 2f4936d9ab88..8dd03acc2f4d 100644 --- a/tests/coverage/coroutine.cov-map +++ b/tests/coverage/coroutine.cov-map @@ -14,12 +14,12 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: coroutine::main -Raw bytes (65): 0x[01, 01, 08, 05, 07, 09, 0d, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 0f, 01, 02, 16, 01, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02] +Raw bytes (65): 0x[01, 01, 08, 07, 0d, 05, 09, 11, 15, 1e, 19, 11, 15, 15, 19, 1e, 19, 11, 15, 09, 01, 0f, 01, 02, 16, 01, 07, 0b, 00, 2e, 11, 01, 2b, 00, 2d, 03, 01, 0e, 00, 35, 11, 02, 0b, 00, 2e, 1e, 01, 22, 00, 27, 1a, 00, 2c, 00, 2e, 17, 01, 0e, 00, 35, 1a, 02, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 8 -- expression 0 operands: lhs = Counter(1), rhs = Expression(1, Add) -- expression 1 operands: lhs = Counter(2), rhs = Counter(3) +- expression 0 operands: lhs = Expression(1, Add), rhs = Counter(3) +- expression 1 operands: lhs = Counter(1), rhs = Counter(2) - expression 2 operands: lhs = Counter(4), rhs = Counter(5) - expression 3 operands: lhs = Expression(7, Sub), rhs = Counter(6) - expression 4 operands: lhs = Counter(4), rhs = Counter(5) @@ -31,7 +31,7 @@ Number of file 0 mappings: 9 - Code(Counter(0)) at (prev + 7, 11) to (start + 0, 46) - Code(Counter(4)) at (prev + 1, 43) to (start + 0, 45) - Code(Expression(0, Add)) at (prev + 1, 14) to (start + 0, 53) - = (c1 + (c2 + c3)) + = ((c1 + c2) + c3) - Code(Counter(4)) at (prev + 2, 11) to (start + 0, 46) - Code(Expression(7, Sub)) at (prev + 1, 34) to (start + 0, 39) = (c4 - c5) diff --git a/tests/coverage/loops_branches.cov-map b/tests/coverage/loops_branches.cov-map index 813583a9de75..8dc35321133b 100644 --- a/tests/coverage/loops_branches.cov-map +++ b/tests/coverage/loops_branches.cov-map @@ -1,5 +1,5 @@ Function name: ::fmt -Raw bytes (249): 0x[01, 01, 31, 05, 00, 00, 02, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, bf, 01, c3, 01, 0d, 00, 11, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, ab, 01, 11, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 25, a3, 01, a6, 01, 19, ab, 01, 11, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, b6, 01, 03, 0d, 00, 0e, bb, 01, 00, 12, 00, 17, b6, 01, 01, 10, 00, 14, b2, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, ae, 01, 01, 12, 00, 13, ab, 01, 01, 11, 00, 22, a6, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 9f, 01, 01, 05, 00, 06] +Raw bytes (249): 0x[01, 01, 31, 05, 00, 00, 02, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, bf, 01, c3, 01, 0d, 00, 11, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, ab, 01, 11, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, a3, 01, 19, 25, a6, 01, ab, 01, 11, 00, ae, 01, b2, 01, 00, b6, 01, 00, bb, 01, 19, bf, 01, c3, 01, 0d, 00, 11, 00, 14, 01, 09, 05, 01, 10, 05, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 02, 01, 0e, 00, 0f, 07, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, 00, 01, 10, 01, 0a, b6, 01, 03, 0d, 00, 0e, bb, 01, 00, 12, 00, 17, b6, 01, 01, 10, 00, 14, b2, 01, 01, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, ae, 01, 01, 12, 00, 13, ab, 01, 01, 11, 00, 22, a6, 01, 00, 22, 00, 23, 00, 01, 14, 01, 0e, 19, 03, 09, 00, 0f, 9f, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 49 @@ -42,8 +42,8 @@ Number of expressions: 49 - expression 36 operands: lhs = Expression(47, Add), rhs = Expression(48, Add) - expression 37 operands: lhs = Counter(3), rhs = Zero - expression 38 operands: lhs = Counter(4), rhs = Zero -- expression 39 operands: lhs = Counter(9), rhs = Expression(40, Add) -- expression 40 operands: lhs = Expression(41, Sub), rhs = Counter(6) +- expression 39 operands: lhs = Expression(40, Add), rhs = Counter(6) +- expression 40 operands: lhs = Counter(9), rhs = Expression(41, Sub) - expression 41 operands: lhs = Expression(42, Add), rhs = Counter(4) - expression 42 operands: lhs = Zero, rhs = Expression(43, Sub) - expression 43 operands: lhs = Expression(44, Sub), rhs = Zero @@ -82,10 +82,10 @@ Number of file 0 mappings: 20 - Code(Zero) at (prev + 1, 20) to (start + 1, 14) - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15) - Code(Expression(39, Add)) at (prev + 1, 5) to (start + 0, 6) - = (c9 + (((Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero)) - c4) + c6)) + = ((c9 + ((Zero + (((((c3 + Zero) + (c4 + Zero)) - c6) - Zero) - Zero)) - c4)) + c6) Function name: ::fmt -Raw bytes (253): 0x[01, 01, 33, 01, 00, 02, 00, 00, 0e, 02, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, c3, 01, c7, 01, 00, 0d, 00, 15, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, b6, 01, 00, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, 00, b2, 01, b6, 01, 00, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, af, 01, 15, 00, b2, 01, b6, 01, 00, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, aa, 01, cb, 01, af, 01, 15, 00, b2, 01, b6, 01, 00, ba, 01, 00, bf, 01, 19, c3, 01, c7, 01, 00, 0d, 00, 15, 19, 25, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 0e, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, ba, 01, 02, 0d, 00, 0e, bf, 01, 00, 12, 00, 17, ba, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, b6, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b2, 01, 01, 12, 00, 13, af, 01, 01, 11, 00, 22, aa, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, a7, 01, 01, 05, 00, 06] +Raw bytes (253): 0x[01, 01, 33, 01, 00, 02, 00, 00, 0e, 02, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, c7, 01, cb, 01, 00, 0d, 00, 15, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, 00, b6, 01, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, b3, 01, 15, 00, b6, 01, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, ab, 01, 25, ae, 01, 19, b3, 01, 15, 00, b6, 01, ba, 01, 00, be, 01, 00, c3, 01, 19, c7, 01, cb, 01, 00, 0d, 00, 15, 14, 01, 22, 05, 01, 11, 00, 01, 12, 01, 0a, 02, 02, 10, 00, 15, 00, 01, 17, 00, 1b, 00, 00, 1c, 00, 1e, 0e, 01, 0e, 00, 0f, 0b, 01, 0d, 00, 1e, 25, 00, 1e, 00, 1f, be, 01, 02, 0d, 00, 0e, c3, 01, 00, 12, 00, 17, be, 01, 01, 10, 00, 15, 00, 00, 16, 01, 0e, ba, 01, 02, 14, 00, 19, 00, 01, 1b, 00, 1f, 00, 00, 20, 00, 22, b6, 01, 01, 12, 00, 13, b3, 01, 01, 11, 00, 22, ae, 01, 00, 22, 00, 23, 19, 03, 09, 00, 0f, a7, 01, 01, 05, 00, 06] Number of files: 1 - file 0 => global file 1 Number of expressions: 51 @@ -93,53 +93,53 @@ Number of expressions: 51 - expression 1 operands: lhs = Expression(0, Sub), rhs = Zero - expression 2 operands: lhs = Zero, rhs = Expression(3, Sub) - expression 3 operands: lhs = Expression(0, Sub), rhs = Zero -- expression 4 operands: lhs = Expression(47, Add), rhs = Counter(6) -- expression 5 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 4 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 5 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) - expression 6 operands: lhs = Zero, rhs = Counter(3) - expression 7 operands: lhs = Zero, rhs = Counter(5) -- expression 8 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 8 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) - expression 9 operands: lhs = Zero, rhs = Counter(3) - expression 10 operands: lhs = Zero, rhs = Counter(5) -- expression 11 operands: lhs = Expression(47, Add), rhs = Counter(6) -- expression 12 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 11 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 12 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) - expression 13 operands: lhs = Zero, rhs = Counter(3) - expression 14 operands: lhs = Zero, rhs = Counter(5) -- expression 15 operands: lhs = Expression(46, Sub), rhs = Zero -- expression 16 operands: lhs = Expression(47, Add), rhs = Counter(6) -- expression 17 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 15 operands: lhs = Expression(47, Sub), rhs = Zero +- expression 16 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 17 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) - expression 18 operands: lhs = Zero, rhs = Counter(3) - expression 19 operands: lhs = Zero, rhs = Counter(5) -- expression 20 operands: lhs = Expression(45, Sub), rhs = Zero -- expression 21 operands: lhs = Expression(46, Sub), rhs = Zero -- expression 22 operands: lhs = Expression(47, Add), rhs = Counter(6) -- expression 23 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 20 operands: lhs = Expression(46, Sub), rhs = Zero +- expression 21 operands: lhs = Expression(47, Sub), rhs = Zero +- expression 22 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 23 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) - expression 24 operands: lhs = Zero, rhs = Counter(3) - expression 25 operands: lhs = Zero, rhs = Counter(5) -- expression 26 operands: lhs = Zero, rhs = Expression(44, Sub) -- expression 27 operands: lhs = Expression(45, Sub), rhs = Zero -- expression 28 operands: lhs = Expression(46, Sub), rhs = Zero -- expression 29 operands: lhs = Expression(47, Add), rhs = Counter(6) -- expression 30 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 26 operands: lhs = Zero, rhs = Expression(45, Sub) +- expression 27 operands: lhs = Expression(46, Sub), rhs = Zero +- expression 28 operands: lhs = Expression(47, Sub), rhs = Zero +- expression 29 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 30 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) - expression 31 operands: lhs = Zero, rhs = Counter(3) - expression 32 operands: lhs = Zero, rhs = Counter(5) -- expression 33 operands: lhs = Expression(43, Add), rhs = Counter(5) -- expression 34 operands: lhs = Zero, rhs = Expression(44, Sub) -- expression 35 operands: lhs = Expression(45, Sub), rhs = Zero -- expression 36 operands: lhs = Expression(46, Sub), rhs = Zero -- expression 37 operands: lhs = Expression(47, Add), rhs = Counter(6) -- expression 38 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) +- expression 33 operands: lhs = Expression(44, Add), rhs = Counter(5) +- expression 34 operands: lhs = Zero, rhs = Expression(45, Sub) +- expression 35 operands: lhs = Expression(46, Sub), rhs = Zero +- expression 36 operands: lhs = Expression(47, Sub), rhs = Zero +- expression 37 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 38 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) - expression 39 operands: lhs = Zero, rhs = Counter(3) - expression 40 operands: lhs = Zero, rhs = Counter(5) -- expression 41 operands: lhs = Expression(42, Sub), rhs = Expression(50, Add) -- expression 42 operands: lhs = Expression(43, Add), rhs = Counter(5) -- expression 43 operands: lhs = Zero, rhs = Expression(44, Sub) -- expression 44 operands: lhs = Expression(45, Sub), rhs = Zero +- expression 41 operands: lhs = Expression(42, Add), rhs = Counter(9) +- expression 42 operands: lhs = Expression(43, Sub), rhs = Counter(6) +- expression 43 operands: lhs = Expression(44, Add), rhs = Counter(5) +- expression 44 operands: lhs = Zero, rhs = Expression(45, Sub) - expression 45 operands: lhs = Expression(46, Sub), rhs = Zero -- expression 46 operands: lhs = Expression(47, Add), rhs = Counter(6) -- expression 47 operands: lhs = Expression(48, Add), rhs = Expression(49, Add) -- expression 48 operands: lhs = Zero, rhs = Counter(3) -- expression 49 operands: lhs = Zero, rhs = Counter(5) -- expression 50 operands: lhs = Counter(6), rhs = Counter(9) +- expression 46 operands: lhs = Expression(47, Sub), rhs = Zero +- expression 47 operands: lhs = Expression(48, Add), rhs = Counter(6) +- expression 48 operands: lhs = Expression(49, Add), rhs = Expression(50, Add) +- expression 49 operands: lhs = Zero, rhs = Counter(3) +- expression 50 operands: lhs = Zero, rhs = Counter(5) Number of file 0 mappings: 20 - Code(Counter(0)) at (prev + 34, 5) to (start + 1, 17) - Code(Zero) at (prev + 1, 18) to (start + 1, 10) @@ -152,26 +152,26 @@ Number of file 0 mappings: 20 - Code(Expression(2, Add)) at (prev + 1, 13) to (start + 0, 30) = (Zero + ((c0 - Zero) - Zero)) - Code(Counter(9)) at (prev + 0, 30) to (start + 0, 31) -- Code(Expression(46, Sub)) at (prev + 2, 13) to (start + 0, 14) +- Code(Expression(47, Sub)) at (prev + 2, 13) to (start + 0, 14) = (((Zero + c3) + (Zero + c5)) - c6) -- Code(Expression(47, Add)) at (prev + 0, 18) to (start + 0, 23) +- Code(Expression(48, Add)) at (prev + 0, 18) to (start + 0, 23) = ((Zero + c3) + (Zero + c5)) -- Code(Expression(46, Sub)) at (prev + 1, 16) to (start + 0, 21) +- Code(Expression(47, Sub)) at (prev + 1, 16) to (start + 0, 21) = (((Zero + c3) + (Zero + c5)) - c6) - Code(Zero) at (prev + 0, 22) to (start + 1, 14) -- Code(Expression(45, Sub)) at (prev + 2, 20) to (start + 0, 25) +- Code(Expression(46, Sub)) at (prev + 2, 20) to (start + 0, 25) = ((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Code(Zero) at (prev + 1, 27) to (start + 0, 31) - Code(Zero) at (prev + 0, 32) to (start + 0, 34) -- Code(Expression(44, Sub)) at (prev + 1, 18) to (start + 0, 19) +- Code(Expression(45, Sub)) at (prev + 1, 18) to (start + 0, 19) = (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero) -- Code(Expression(43, Add)) at (prev + 1, 17) to (start + 0, 34) +- Code(Expression(44, Add)) at (prev + 1, 17) to (start + 0, 34) = (Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)) -- Code(Expression(42, Sub)) at (prev + 0, 34) to (start + 0, 35) +- Code(Expression(43, Sub)) at (prev + 0, 34) to (start + 0, 35) = ((Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)) - c5) - Code(Counter(6)) at (prev + 3, 9) to (start + 0, 15) - Code(Expression(41, Add)) at (prev + 1, 5) to (start + 0, 6) - = (((Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)) - c5) + (c6 + c9)) + = ((((Zero + (((((Zero + c3) + (Zero + c5)) - c6) - Zero) - Zero)) - c5) + c6) + c9) Function name: loops_branches::main Raw bytes (9): 0x[01, 01, 00, 01, 01, 37, 01, 05, 02] diff --git a/tests/coverage/try_error_result.cov-map b/tests/coverage/try_error_result.cov-map index 8367103a21a4..a9a18a180ddd 100644 --- a/tests/coverage/try_error_result.cov-map +++ b/tests/coverage/try_error_result.cov-map @@ -59,7 +59,7 @@ Number of file 0 mappings: 4 = (c1 + (c0 - c1)) Function name: try_error_result::test1 -Raw bytes (77): 0x[01, 01, 09, 01, 07, 05, 09, 03, 0d, 1d, 11, 16, 1d, 03, 0d, 1f, 0d, 11, 23, 15, 19, 0b, 01, 0c, 01, 02, 17, 03, 07, 09, 00, 0e, 16, 02, 09, 04, 1a, 1d, 06, 0d, 00, 29, 11, 00, 29, 00, 2a, 0e, 01, 0d, 00, 2a, 15, 00, 2a, 00, 2b, 12, 04, 0d, 00, 2a, 19, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 1b, 01, 01, 00, 02] +Raw bytes (77): 0x[01, 01, 09, 01, 07, 05, 09, 03, 0d, 1d, 11, 16, 1d, 03, 0d, 1f, 0d, 23, 19, 11, 15, 0b, 01, 0c, 01, 02, 17, 03, 07, 09, 00, 0e, 16, 02, 09, 04, 1a, 1d, 06, 0d, 00, 29, 11, 00, 29, 00, 2a, 0e, 01, 0d, 00, 2a, 15, 00, 2a, 00, 2b, 12, 04, 0d, 00, 2a, 19, 00, 2a, 00, 2b, 0d, 03, 05, 00, 0b, 1b, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 9 @@ -70,8 +70,8 @@ Number of expressions: 9 - expression 4 operands: lhs = Expression(5, Sub), rhs = Counter(7) - expression 5 operands: lhs = Expression(0, Add), rhs = Counter(3) - expression 6 operands: lhs = Expression(7, Add), rhs = Counter(3) -- expression 7 operands: lhs = Counter(4), rhs = Expression(8, Add) -- expression 8 operands: lhs = Counter(5), rhs = Counter(6) +- expression 7 operands: lhs = Expression(8, Add), rhs = Counter(6) +- expression 8 operands: lhs = Counter(4), rhs = Counter(5) Number of file 0 mappings: 11 - Code(Counter(0)) at (prev + 12, 1) to (start + 2, 23) - Code(Expression(0, Add)) at (prev + 7, 9) to (start + 0, 14) @@ -88,10 +88,10 @@ Number of file 0 mappings: 11 - Code(Counter(6)) at (prev + 0, 42) to (start + 0, 43) - Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11) - Code(Expression(6, Add)) at (prev + 1, 1) to (start + 0, 2) - = ((c4 + (c5 + c6)) + c3) + = (((c4 + c5) + c6) + c3) Function name: try_error_result::test2 -Raw bytes (358): 0x[01, 01, 3b, 01, 07, 05, 09, 03, 0d, 41, 11, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 4a, 15, 41, 11, 46, 19, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 5e, 25, 49, 21, 49, 21, 5e, 25, 49, 21, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, 92, 01, 41, 03, 0d, 8e, 01, 29, 92, 01, 41, 03, 0d, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, a6, 01, 35, 45, 31, 45, 31, a6, 01, 35, 45, 31, ba, 01, 3d, 4d, 39, 4d, 39, ba, 01, 3d, 4d, 39, c3, 01, 0d, 11, c7, 01, cb, 01, db, 01, 15, cf, 01, d3, 01, d7, 01, 19, 1d, 21, 25, df, 01, e3, 01, 29, 2d, e7, 01, eb, 01, 31, 35, 39, 3d, 28, 01, 3c, 01, 03, 17, 03, 08, 09, 00, 0e, 92, 01, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 11, 00, 2f, 00, 30, 4a, 00, 31, 03, 35, 15, 04, 11, 00, 12, 46, 02, 11, 04, 12, 3e, 05, 11, 00, 14, 46, 00, 17, 00, 41, 19, 00, 41, 00, 42, 42, 00, 43, 00, 5f, 1d, 00, 5f, 00, 60, 3e, 01, 0d, 00, 20, 5a, 01, 11, 00, 14, 49, 00, 17, 00, 41, 21, 00, 41, 00, 42, 5e, 00, 43, 00, 60, 25, 00, 60, 00, 61, 5a, 01, 0d, 00, 20, 86, 01, 04, 11, 00, 14, 8e, 01, 00, 17, 00, 42, 29, 00, 42, 00, 43, 8a, 01, 00, 44, 00, 61, 2d, 00, 61, 00, 62, 86, 01, 01, 0d, 00, 20, a2, 01, 01, 11, 00, 14, 45, 00, 17, 01, 36, 31, 01, 36, 00, 37, a6, 01, 01, 12, 00, 2f, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 20, b6, 01, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 39, 02, 11, 00, 12, ba, 01, 01, 12, 00, 2f, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, bf, 01, 01, 01, 00, 02] +Raw bytes (358): 0x[01, 01, 3b, 01, 07, 05, 09, 03, 0d, 41, 11, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 4a, 15, 41, 11, 46, 19, 4a, 15, 41, 11, 42, 1d, 46, 19, 4a, 15, 41, 11, 5e, 25, 49, 21, 49, 21, 5e, 25, 49, 21, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, 92, 01, 41, 03, 0d, 8e, 01, 29, 92, 01, 41, 03, 0d, 8a, 01, 2d, 8e, 01, 29, 92, 01, 41, 03, 0d, a6, 01, 35, 45, 31, 45, 31, a6, 01, 35, 45, 31, ba, 01, 3d, 4d, 39, 4d, 39, ba, 01, 3d, 4d, 39, c3, 01, 0d, c7, 01, db, 01, cb, 01, cf, 01, 11, 15, d3, 01, d7, 01, 19, 1d, 21, 25, df, 01, e3, 01, 29, 2d, e7, 01, eb, 01, 31, 35, 39, 3d, 28, 01, 3c, 01, 03, 17, 03, 08, 09, 00, 0e, 92, 01, 02, 09, 04, 1a, 41, 06, 0d, 00, 2f, 11, 00, 2f, 00, 30, 4a, 00, 31, 03, 35, 15, 04, 11, 00, 12, 46, 02, 11, 04, 12, 3e, 05, 11, 00, 14, 46, 00, 17, 00, 41, 19, 00, 41, 00, 42, 42, 00, 43, 00, 5f, 1d, 00, 5f, 00, 60, 3e, 01, 0d, 00, 20, 5a, 01, 11, 00, 14, 49, 00, 17, 00, 41, 21, 00, 41, 00, 42, 5e, 00, 43, 00, 60, 25, 00, 60, 00, 61, 5a, 01, 0d, 00, 20, 86, 01, 04, 11, 00, 14, 8e, 01, 00, 17, 00, 42, 29, 00, 42, 00, 43, 8a, 01, 00, 44, 00, 61, 2d, 00, 61, 00, 62, 86, 01, 01, 0d, 00, 20, a2, 01, 01, 11, 00, 14, 45, 00, 17, 01, 36, 31, 01, 36, 00, 37, a6, 01, 01, 12, 00, 2f, 35, 00, 2f, 00, 30, a2, 01, 01, 0d, 00, 20, b6, 01, 01, 11, 00, 14, 4d, 00, 17, 01, 36, 39, 02, 11, 00, 12, ba, 01, 01, 12, 00, 2f, 3d, 01, 11, 00, 12, b6, 01, 02, 0d, 00, 20, 0d, 03, 05, 00, 0b, bf, 01, 01, 01, 00, 02] Number of files: 1 - file 0 => global file 1 Number of expressions: 59 @@ -143,9 +143,9 @@ Number of expressions: 59 - expression 45 operands: lhs = Expression(46, Sub), rhs = Counter(15) - expression 46 operands: lhs = Counter(19), rhs = Counter(14) - expression 47 operands: lhs = Expression(48, Add), rhs = Counter(3) -- expression 48 operands: lhs = Counter(4), rhs = Expression(49, Add) -- expression 49 operands: lhs = Expression(50, Add), rhs = Expression(54, Add) -- expression 50 operands: lhs = Counter(5), rhs = Expression(51, Add) +- expression 48 operands: lhs = Expression(49, Add), rhs = Expression(54, Add) +- expression 49 operands: lhs = Expression(50, Add), rhs = Expression(51, Add) +- expression 50 operands: lhs = Counter(4), rhs = Counter(5) - expression 51 operands: lhs = Expression(52, Add), rhs = Expression(53, Add) - expression 52 operands: lhs = Counter(6), rhs = Counter(7) - expression 53 operands: lhs = Counter(8), rhs = Counter(9) @@ -216,5 +216,5 @@ Number of file 0 mappings: 40 = ((c19 - c14) - c15) - Code(Counter(3)) at (prev + 3, 5) to (start + 0, 11) - Code(Expression(47, Add)) at (prev + 1, 1) to (start + 0, 2) - = ((c4 + ((c5 + ((c6 + c7) + (c8 + c9))) + ((c10 + c11) + ((c12 + c13) + (c14 + c15))))) + c3) + = ((((c4 + c5) + ((c6 + c7) + (c8 + c9))) + ((c10 + c11) + ((c12 + c13) + (c14 + c15)))) + c3) From 276a32994e30aeca2cd7f5039009e9cd7b6f2e00 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Mon, 30 Oct 2023 20:54:19 +1100 Subject: [PATCH 50/93] coverage: Extract `CoverageGraph::bcb_has_multiple_in_edges` This was previously a helper method in `MakeBcbCounters`, but putting it in the graph lets us call it from `BcbBranch`, and gives us a more fine-grained borrow. --- .../rustc_mir_transform/src/coverage/counters.rs | 9 +-------- .../rustc_mir_transform/src/coverage/graph.rs | 16 +++++++++++++++- 2 files changed, 16 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index ca7feb942fe5..b5fba797dc42 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -341,7 +341,7 @@ impl<'a> MakeBcbCounters<'a> { // A BCB with only one incoming edge gets a simple `Counter` (via `make_counter()`). // Also, a BCB that loops back to itself gets a simple `Counter`. This may indicate the // program results in a tight infinite loop, but it should still compile. - let one_path_to_target = self.bcb_has_one_path_to_target(bcb); + let one_path_to_target = !self.basic_coverage_blocks.bcb_has_multiple_in_edges(bcb); if one_path_to_target || self.bcb_predecessors(bcb).contains(&bcb) { let counter_kind = self.coverage_counters.make_counter(); if one_path_to_target { @@ -510,11 +510,4 @@ impl<'a> MakeBcbCounters<'a> { self.coverage_counters.bcb_counters[to_bcb].as_ref() } } - - /// Returns true if the BasicCoverageBlock has zero or one incoming edge. (If zero, it should be - /// the entry point for the function.) - #[inline] - fn bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool { - self.bcb_predecessors(bcb).len() <= 1 - } } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 0d807db404c8..b3a69e9fa829 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -199,6 +199,20 @@ impl CoverageGraph { pub fn cmp_in_dominator_order(&self, a: BasicCoverageBlock, b: BasicCoverageBlock) -> Ordering { self.dominators.as_ref().unwrap().cmp_in_dominator_order(a, b) } + + /// Returns true if the given node has 2 or more in-edges, i.e. 2 or more + /// predecessors. + /// + /// This property is interesting to code that assigns counters to nodes and + /// edges, because if a node _doesn't_ have multiple in-edges, then there's + /// no benefit in having a separate counter for its in-edge, because it + /// would have the same value as the node's own counter. + /// + /// FIXME: That assumption might not be true for [`TerminatorKind::Yield`]? + #[inline(always)] + pub(super) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool { + self.predecessors[bcb].len() > 1 + } } impl Index for CoverageGraph { @@ -335,7 +349,7 @@ impl BcbBranch { to_bcb: BasicCoverageBlock, basic_coverage_blocks: &CoverageGraph, ) -> Self { - let edge_from_bcb = if basic_coverage_blocks.predecessors[to_bcb].len() > 1 { + let edge_from_bcb = if basic_coverage_blocks.bcb_has_multiple_in_edges(from_bcb) { Some(from_bcb) } else { None From 3b9d7037c9aa22b06620499c548f5c53b104de33 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 1 Nov 2023 11:40:12 +1100 Subject: [PATCH 51/93] coverage: Eliminate `BcbBranch` `BcbBranch` represented an out-edge of a coverage graph node, but would silently refer to a node instead in cases where that node only had one in-edge. Instead we now refer to a graph edge as a `(from_bcb, to_bcb)` pair, or sometimes as just one of those nodes when the other node is implied by the surrounding context. The case of sole in-edges is handled by special code added directly to `get_or_make_edge_counter_operand`. --- .../src/coverage/counters.rs | 134 +++++++++--------- .../rustc_mir_transform/src/coverage/graph.rs | 39 ----- 2 files changed, 69 insertions(+), 104 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index b5fba797dc42..604589e5b96b 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -1,13 +1,11 @@ -use super::graph; - -use graph::{BasicCoverageBlock, BcbBranch, CoverageGraph, TraverseCoverageGraphWithLoops}; - use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::graph::WithNumNodes; use rustc_index::bit_set::BitSet; use rustc_index::IndexVec; use rustc_middle::mir::coverage::*; +use super::graph::{BasicCoverageBlock, CoverageGraph, TraverseCoverageGraphWithLoops}; + use std::fmt::{self, Debug}; /// The coverage counter or counter expression associated with a particular @@ -259,49 +257,46 @@ impl<'a> MakeBcbCounters<'a> { // We might also use its term later to compute one of the branch counters. let from_bcb_operand = self.get_or_make_counter_operand(from_bcb); - let branches = self.bcb_branches(from_bcb); + let branch_target_bcbs = self.basic_coverage_blocks.successors[from_bcb].as_slice(); // If this node doesn't have multiple out-edges, or all of its out-edges // already have counters, then we don't need to create edge counters. - let needs_branch_counters = - branches.len() > 1 && branches.iter().any(|branch| self.branch_has_no_counter(branch)); + let needs_branch_counters = branch_target_bcbs.len() > 1 + && branch_target_bcbs + .iter() + .any(|&to_bcb| self.branch_has_no_counter(from_bcb, to_bcb)); if !needs_branch_counters { return; } debug!( "{from_bcb:?} has some branch(es) without counters:\n {}", - branches + branch_target_bcbs .iter() - .map(|branch| { format!("{:?}: {:?}", branch, self.branch_counter(branch)) }) + .map(|&to_bcb| { + format!("{from_bcb:?}->{to_bcb:?}: {:?}", self.branch_counter(from_bcb, to_bcb)) + }) .collect::>() .join("\n "), ); - // Use the `traversal` state to decide if a subset of the branches exit a loop, making it - // likely that branch is executed less than branches that do not exit the same loop. In this - // case, any branch that does not exit the loop (and has not already been assigned a - // counter) should be counted by expression, if possible. (If a preferred expression branch - // is not selected based on the loop context, select any branch without an existing - // counter.) - let expression_branch = self.choose_preferred_expression_branch(traversal, &branches); + // Of the branch edges that don't have counters yet, one can be given an expression + // (computed from the other edges) instead of a dedicated counter. + let expression_to_bcb = self.choose_preferred_expression_branch(traversal, from_bcb); // For each branch arm other than the one that was chosen to get an expression, // ensure that it has a counter (existing counter/expression or a new counter), // and accumulate the corresponding terms into a single sum term. let sum_of_all_other_branches: BcbCounter = { - let _span = debug_span!("sum_of_all_other_branches", ?expression_branch).entered(); - branches - .into_iter() + let _span = debug_span!("sum_of_all_other_branches", ?expression_to_bcb).entered(); + branch_target_bcbs + .iter() + .copied() // Skip the chosen branch, since we'll calculate it from the other branches. - .filter(|branch| branch != &expression_branch) - .fold(None, |accum, branch| { - let _span = debug_span!("branch", ?accum, ?branch).entered(); - let branch_counter = if branch.is_only_path_to_target() { - self.get_or_make_counter_operand(branch.target_bcb) - } else { - self.get_or_make_edge_counter_operand(from_bcb, branch.target_bcb) - }; + .filter(|&to_bcb| to_bcb != expression_to_bcb) + .fold(None, |accum, to_bcb| { + let _span = debug_span!("to_bcb", ?accum, ?to_bcb).entered(); + let branch_counter = self.get_or_make_edge_counter_operand(from_bcb, to_bcb); Some(self.coverage_counters.make_sum_expression(accum, branch_counter)) }) .expect("there must be at least one other branch") @@ -311,22 +306,20 @@ impl<'a> MakeBcbCounters<'a> { // by taking the count of the node we're branching from, and subtracting the // sum of all the other branches. debug!( - "Making an expression for the selected expression_branch: {:?} \ - (expression_branch predecessors: {:?})", - expression_branch, - self.bcb_predecessors(expression_branch.target_bcb), + "Making an expression for the selected expression_branch: \ + {expression_to_bcb:?} (expression_branch predecessors: {:?})", + self.bcb_predecessors(expression_to_bcb), ); let expression = self.coverage_counters.make_expression( from_bcb_operand, Op::Subtract, sum_of_all_other_branches, ); - debug!("{:?} gets an expression: {:?}", expression_branch, expression); - let bcb = expression_branch.target_bcb; - if expression_branch.is_only_path_to_target() { - self.coverage_counters.set_bcb_counter(bcb, expression); + debug!("{expression_to_bcb:?} gets an expression: {expression:?}"); + if self.basic_coverage_blocks.bcb_has_multiple_in_edges(expression_to_bcb) { + self.coverage_counters.set_bcb_edge_counter(from_bcb, expression_to_bcb, expression); } else { - self.coverage_counters.set_bcb_edge_counter(from_bcb, bcb, expression); + self.coverage_counters.set_bcb_counter(expression_to_bcb, expression); } } @@ -383,10 +376,16 @@ impl<'a> MakeBcbCounters<'a> { from_bcb: BasicCoverageBlock, to_bcb: BasicCoverageBlock, ) -> BcbCounter { + // If the target BCB has only one in-edge (i.e. this one), then create + // a node counter instead, since it will have the same value. + if !self.basic_coverage_blocks.bcb_has_multiple_in_edges(to_bcb) { + assert_eq!([from_bcb].as_slice(), self.basic_coverage_blocks.predecessors[to_bcb]); + return self.get_or_make_counter_operand(to_bcb); + } + // If the source BCB has only one successor (assumed to be the given target), an edge // counter is unnecessary. Just get or make a counter for the source BCB. - let successors = self.bcb_successors(from_bcb).iter(); - if successors.len() == 1 { + if self.bcb_successors(from_bcb).len() == 1 { return self.get_or_make_counter_operand(from_bcb); } @@ -409,16 +408,19 @@ impl<'a> MakeBcbCounters<'a> { fn choose_preferred_expression_branch( &self, traversal: &TraverseCoverageGraphWithLoops<'_>, - branches: &[BcbBranch], - ) -> BcbBranch { - let good_reloop_branch = self.find_good_reloop_branch(traversal, branches); - if let Some(reloop_branch) = good_reloop_branch { - assert!(self.branch_has_no_counter(&reloop_branch)); - debug!("Selecting reloop branch {reloop_branch:?} to get an expression"); - reloop_branch + from_bcb: BasicCoverageBlock, + ) -> BasicCoverageBlock { + let good_reloop_branch = self.find_good_reloop_branch(traversal, from_bcb); + if let Some(reloop_target) = good_reloop_branch { + assert!(self.branch_has_no_counter(from_bcb, reloop_target)); + debug!("Selecting reloop target {reloop_target:?} to get an expression"); + reloop_target } else { - let &branch_without_counter = - branches.iter().find(|&branch| self.branch_has_no_counter(branch)).expect( + let &branch_without_counter = self + .bcb_successors(from_bcb) + .iter() + .find(|&&to_bcb| self.branch_has_no_counter(from_bcb, to_bcb)) + .expect( "needs_branch_counters was `true` so there should be at least one \ branch", ); @@ -439,26 +441,28 @@ impl<'a> MakeBcbCounters<'a> { fn find_good_reloop_branch( &self, traversal: &TraverseCoverageGraphWithLoops<'_>, - branches: &[BcbBranch], - ) -> Option { + from_bcb: BasicCoverageBlock, + ) -> Option { + let branch_target_bcbs = self.bcb_successors(from_bcb); + // Consider each loop on the current traversal context stack, top-down. for reloop_bcbs in traversal.reloop_bcbs_per_loop() { let mut all_branches_exit_this_loop = true; // Try to find a branch that doesn't exit this loop and doesn't // already have a counter. - for &branch in branches { + for &branch_target_bcb in branch_target_bcbs { // A branch is a reloop branch if it dominates any BCB that has // an edge back to the loop header. (Other branches are exits.) let is_reloop_branch = reloop_bcbs.iter().any(|&reloop_bcb| { - self.basic_coverage_blocks.dominates(branch.target_bcb, reloop_bcb) + self.basic_coverage_blocks.dominates(branch_target_bcb, reloop_bcb) }); if is_reloop_branch { all_branches_exit_this_loop = false; - if self.branch_has_no_counter(&branch) { + if self.branch_has_no_counter(from_bcb, branch_target_bcb) { // We found a good branch to be given an expression. - return Some(branch); + return Some(branch_target_bcb); } // Keep looking for another reloop branch without a counter. } else { @@ -491,20 +495,20 @@ impl<'a> MakeBcbCounters<'a> { } #[inline] - fn bcb_branches(&self, from_bcb: BasicCoverageBlock) -> Vec { - self.bcb_successors(from_bcb) - .iter() - .map(|&to_bcb| BcbBranch::from_to(from_bcb, to_bcb, self.basic_coverage_blocks)) - .collect::>() + fn branch_has_no_counter( + &self, + from_bcb: BasicCoverageBlock, + to_bcb: BasicCoverageBlock, + ) -> bool { + self.branch_counter(from_bcb, to_bcb).is_none() } - fn branch_has_no_counter(&self, branch: &BcbBranch) -> bool { - self.branch_counter(branch).is_none() - } - - fn branch_counter(&self, branch: &BcbBranch) -> Option<&BcbCounter> { - let to_bcb = branch.target_bcb; - if let Some(from_bcb) = branch.edge_from_bcb { + fn branch_counter( + &self, + from_bcb: BasicCoverageBlock, + to_bcb: BasicCoverageBlock, + ) -> Option<&BcbCounter> { + if self.basic_coverage_blocks.bcb_has_multiple_in_edges(to_bcb) { self.coverage_counters.bcb_edge_counters.get(&(from_bcb, to_bcb)) } else { self.coverage_counters.bcb_counters[to_bcb].as_ref() diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index b3a69e9fa829..34ab2992e3b3 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -333,45 +333,6 @@ impl BasicCoverageBlockData { } } -/// Represents a successor from a branching BasicCoverageBlock (such as the arms of a `SwitchInt`) -/// as either the successor BCB itself, if it has only one incoming edge, or the successor _plus_ -/// the specific branching BCB, representing the edge between the two. The latter case -/// distinguishes this incoming edge from other incoming edges to the same `target_bcb`. -#[derive(Clone, Copy, PartialEq, Eq)] -pub(super) struct BcbBranch { - pub edge_from_bcb: Option, - pub target_bcb: BasicCoverageBlock, -} - -impl BcbBranch { - pub fn from_to( - from_bcb: BasicCoverageBlock, - to_bcb: BasicCoverageBlock, - basic_coverage_blocks: &CoverageGraph, - ) -> Self { - let edge_from_bcb = if basic_coverage_blocks.bcb_has_multiple_in_edges(from_bcb) { - Some(from_bcb) - } else { - None - }; - Self { edge_from_bcb, target_bcb: to_bcb } - } - - pub fn is_only_path_to_target(&self) -> bool { - self.edge_from_bcb.is_none() - } -} - -impl std::fmt::Debug for BcbBranch { - fn fmt(&self, fmt: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { - if let Some(from_bcb) = self.edge_from_bcb { - write!(fmt, "{:?}->{:?}", from_bcb, self.target_bcb) - } else { - write!(fmt, "{:?}", self.target_bcb) - } - } -} - // Returns the subset of a block's successors that are relevant to the coverage // graph, i.e. those that do not represent unwinds or unreachable branches. // FIXME(#78544): MIR InstrumentCoverage: Improve coverage of `#[should_panic]` tests and From 3163bc870016ac42f2204057f7e43ec81674aba1 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Sun, 5 Nov 2023 22:21:22 +1100 Subject: [PATCH 52/93] coverage: Assert that bcb0 starts with bb0 and has no in-edges This explains why we don't have to worry about bcb0 having multiple in-edges. --- compiler/rustc_mir_transform/src/coverage/graph.rs | 13 +++++++++++++ 1 file changed, 13 insertions(+) diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 34ab2992e3b3..263bfdaaabab 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -62,6 +62,14 @@ impl CoverageGraph { Self { bcbs, bb_to_bcb, successors, predecessors, dominators: None }; let dominators = dominators::dominators(&basic_coverage_blocks); basic_coverage_blocks.dominators = Some(dominators); + + // The coverage graph's entry-point node (bcb0) always starts with bb0, + // which never has predecessors. Any other blocks merged into bcb0 can't + // have multiple (coverage-relevant) predecessors, so bcb0 always has + // zero in-edges. + assert!(basic_coverage_blocks[START_BCB].leader_bb() == mir::START_BLOCK); + assert!(basic_coverage_blocks.predecessors[START_BCB].is_empty()); + basic_coverage_blocks } @@ -211,6 +219,11 @@ impl CoverageGraph { /// FIXME: That assumption might not be true for [`TerminatorKind::Yield`]? #[inline(always)] pub(super) fn bcb_has_multiple_in_edges(&self, bcb: BasicCoverageBlock) -> bool { + // Even though bcb0 conceptually has an extra virtual in-edge due to + // being the entry point, we've already asserted that it has no _other_ + // in-edges, so there's no possibility of it having _multiple_ in-edges. + // (And since its virtual in-edge doesn't exist in the graph, that edge + // can't have a separate counter anyway.) self.predecessors[bcb].len() > 1 } } From 9b013bb3b8dc30b66f82feeb92be67e8aec7256f Mon Sep 17 00:00:00 2001 From: Weihang Lo Date: Fri, 24 Nov 2023 23:13:09 -0500 Subject: [PATCH 53/93] Update cargo This removes the check to ensure that `rustfix` between * src/tools/cargo * src/tools/compiletest has the same version, since `rust-lang/rustfix` has migrated to under `rust-lang/cargo`. --- src/tools/cargo | 2 +- src/tools/tidy/src/deps.rs | 40 -------------------------------------- 2 files changed, 1 insertion(+), 41 deletions(-) diff --git a/src/tools/cargo b/src/tools/cargo index 71cd3a926f0c..9b13310ca596 160000 --- a/src/tools/cargo +++ b/src/tools/cargo @@ -1 +1 @@ -Subproject commit 71cd3a926f0cf41eeaf9f2a7f2194b2aff85b0f6 +Subproject commit 9b13310ca596020a737aaa47daa4ed9ff8898a2f diff --git a/src/tools/tidy/src/deps.rs b/src/tools/tidy/src/deps.rs index 102155202278..f36893bfb94c 100644 --- a/src/tools/tidy/src/deps.rs +++ b/src/tools/tidy/src/deps.rs @@ -488,7 +488,6 @@ const PERMITTED_CRANELIFT_DEPENDENCIES: &[&str] = &[ /// to the cargo executable. pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { let mut checked_runtime_licenses = false; - let mut rust_metadata = None; for &(workspace, exceptions, permitted_deps) in WORKSPACES { if !root.join(workspace).join("Cargo.lock").exists() { @@ -512,15 +511,6 @@ pub fn check(root: &Path, cargo: &Path, bad: &mut bool) { let runtime_ids = compute_runtime_crates(&metadata); check_runtime_license_exceptions(&metadata, runtime_ids, bad); checked_runtime_licenses = true; - rust_metadata = Some(metadata); - } else if workspace == "src/tools/cargo" { - check_rustfix( - rust_metadata - .as_ref() - .expect("The root workspace should be the first to be checked"), - &metadata, - bad, - ); } } @@ -749,33 +739,3 @@ fn deps_of_filtered<'a>( deps_of_filtered(metadata, &dep.pkg, result, filter); } } - -fn direct_deps_of<'a>( - metadata: &'a Metadata, - pkg_id: &'a PackageId, -) -> impl Iterator { - let resolve = metadata.resolve.as_ref().unwrap(); - let node = resolve.nodes.iter().find(|n| &n.id == pkg_id).unwrap(); - node.deps.iter().map(|dep| pkg_from_id(metadata, &dep.pkg)) -} - -fn check_rustfix(rust_metadata: &Metadata, cargo_metadata: &Metadata, bad: &mut bool) { - let cargo = pkg_from_name(cargo_metadata, "cargo"); - let cargo_rustfix = - direct_deps_of(cargo_metadata, &cargo.id).find(|p| p.name == "rustfix").unwrap(); - - let compiletest = pkg_from_name(rust_metadata, "compiletest"); - let compiletest_rustfix = - direct_deps_of(rust_metadata, &compiletest.id).find(|p| p.name == "rustfix").unwrap(); - - if cargo_rustfix.version != compiletest_rustfix.version { - tidy_error!( - bad, - "cargo's rustfix version {} does not match compiletest's rustfix version {}\n\ - rustfix should be kept in sync, update the cargo side first, and then update \ - compiletest along with cargo.", - cargo_rustfix.version, - compiletest_rustfix.version - ); - } -} From e6e2f00d2196281bdd92c3dbfb466687708807c3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 25 Nov 2023 09:14:19 +0000 Subject: [PATCH 54/93] Fix incorrect implementation of several vendor intrinsics --- src/intrinsics/llvm_x86.rs | 32 ++++++++++++++++---------------- 1 file changed, 16 insertions(+), 16 deletions(-) diff --git a/src/intrinsics/llvm_x86.rs b/src/intrinsics/llvm_x86.rs index 2108b4bb9ffe..07b95b7933d0 100644 --- a/src/intrinsics/llvm_x86.rs +++ b/src/intrinsics/llvm_x86.rs @@ -556,12 +556,12 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( let ret_lane_layout = fx.layout_of(fx.tcx.types.i32); for out_lane_idx in 0..lane_count / 2 { let a_lane0 = a.value_lane(fx, out_lane_idx * 2).load_scalar(fx); - let a_lane0 = fx.bcx.ins().uextend(types::I32, a_lane0); + let a_lane0 = fx.bcx.ins().sextend(types::I32, a_lane0); let b_lane0 = b.value_lane(fx, out_lane_idx * 2).load_scalar(fx); let b_lane0 = fx.bcx.ins().sextend(types::I32, b_lane0); let a_lane1 = a.value_lane(fx, out_lane_idx * 2 + 1).load_scalar(fx); - let a_lane1 = fx.bcx.ins().uextend(types::I32, a_lane1); + let a_lane1 = fx.bcx.ins().sextend(types::I32, a_lane1); let b_lane1 = b.value_lane(fx, out_lane_idx * 2 + 1).load_scalar(fx); let b_lane1 = fx.bcx.ins().sextend(types::I32, b_lane1); @@ -716,14 +716,14 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( assert_eq!(ret_lane_ty, fx.tcx.types.i16); assert_eq!(lane_count * 2, ret_lane_count); - let min_i16 = fx.bcx.ins().iconst(types::I32, i64::from(i16::MIN as u16)); - let max_i16 = fx.bcx.ins().iconst(types::I32, i64::from(i16::MAX as u16)); + let min_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MIN) as u32 as i64); + let max_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MAX) as u32 as i64); let ret_lane_layout = fx.layout_of(fx.tcx.types.i16); for idx in 0..lane_count { let lane = a.value_lane(fx, idx).load_scalar(fx); let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().umin(sat, max_i16); + let sat = fx.bcx.ins().smin(sat, max_i16); let res = fx.bcx.ins().ireduce(types::I16, sat); let res_lane = CValue::by_val(res, ret_lane_layout); @@ -733,7 +733,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( for idx in 0..lane_count { let lane = b.value_lane(fx, idx).load_scalar(fx); let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().umin(sat, max_i16); + let sat = fx.bcx.ins().smin(sat, max_i16); let res = fx.bcx.ins().ireduce(types::I16, sat); let res_lane = CValue::by_val(res, ret_lane_layout); @@ -760,8 +760,8 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( for idx in 0..lane_count { let lane = a.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().umax(lane, min_u16); - let sat = fx.bcx.ins().umin(sat, max_u16); + let sat = fx.bcx.ins().smax(lane, min_u16); + let sat = fx.bcx.ins().smin(sat, max_u16); let res = fx.bcx.ins().ireduce(types::I16, sat); let res_lane = CValue::by_val(res, ret_lane_layout); @@ -770,8 +770,8 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( for idx in 0..lane_count { let lane = b.value_lane(fx, idx).load_scalar(fx); - let sat = fx.bcx.ins().umax(lane, min_u16); - let sat = fx.bcx.ins().umin(sat, max_u16); + let sat = fx.bcx.ins().smax(lane, min_u16); + let sat = fx.bcx.ins().smin(sat, max_u16); let res = fx.bcx.ins().ireduce(types::I16, sat); let res_lane = CValue::by_val(res, ret_lane_layout); @@ -792,14 +792,14 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( assert_eq!(ret_lane_ty, fx.tcx.types.i16); assert_eq!(lane_count * 2, ret_lane_count); - let min_i16 = fx.bcx.ins().iconst(types::I32, i64::from(i16::MIN as u16)); - let max_i16 = fx.bcx.ins().iconst(types::I32, i64::from(i16::MAX as u16)); + let min_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MIN) as u32 as i64); + let max_i16 = fx.bcx.ins().iconst(types::I32, i32::from(i16::MAX) as u32 as i64); let ret_lane_layout = fx.layout_of(fx.tcx.types.i16); for idx in 0..lane_count / 2 { let lane = a.value_lane(fx, idx).load_scalar(fx); let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().umin(sat, max_i16); + let sat = fx.bcx.ins().smin(sat, max_i16); let res = fx.bcx.ins().ireduce(types::I16, sat); let res_lane = CValue::by_val(res, ret_lane_layout); @@ -809,7 +809,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( for idx in 0..lane_count / 2 { let lane = b.value_lane(fx, idx).load_scalar(fx); let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().umin(sat, max_i16); + let sat = fx.bcx.ins().smin(sat, max_i16); let res = fx.bcx.ins().ireduce(types::I16, sat); let res_lane = CValue::by_val(res, ret_lane_layout); @@ -819,7 +819,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( for idx in 0..lane_count / 2 { let lane = a.value_lane(fx, idx).load_scalar(fx); let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().umin(sat, max_i16); + let sat = fx.bcx.ins().smin(sat, max_i16); let res = fx.bcx.ins().ireduce(types::I16, sat); let res_lane = CValue::by_val(res, ret_lane_layout); @@ -829,7 +829,7 @@ pub(crate) fn codegen_x86_llvm_intrinsic_call<'tcx>( for idx in 0..lane_count / 2 { let lane = b.value_lane(fx, idx).load_scalar(fx); let sat = fx.bcx.ins().smax(lane, min_i16); - let sat = fx.bcx.ins().umin(sat, max_i16); + let sat = fx.bcx.ins().smin(sat, max_i16); let res = fx.bcx.ins().ireduce(types::I16, sat); let res_lane = CValue::by_val(res, ret_lane_layout); From da3782a0b4aa6ad31a2e59a17eb712f4ea190a91 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 25 Nov 2023 09:32:50 +0000 Subject: [PATCH 55/93] Rustup to rustc 1.76.0-nightly (37b2813a7 2023-11-24) --- rust-toolchain | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/rust-toolchain b/rust-toolchain index 80ef1e49f231..2997816d96c7 100644 --- a/rust-toolchain +++ b/rust-toolchain @@ -1,3 +1,3 @@ [toolchain] -channel = "nightly-2023-11-16" +channel = "nightly-2023-11-25" components = ["rust-src", "rustc-dev", "llvm-tools"] From 86fc533a7155179f490649571174bc1470edb97b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 25 Nov 2023 09:40:02 +0000 Subject: [PATCH 56/93] Re-enable rustc test that was disabled due to a rustc bug --- scripts/test_rustc_tests.sh | 5 ----- 1 file changed, 5 deletions(-) diff --git a/scripts/test_rustc_tests.sh b/scripts/test_rustc_tests.sh index cdc78adcf85e..a299b6de6b1c 100755 --- a/scripts/test_rustc_tests.sh +++ b/scripts/test_rustc_tests.sh @@ -146,11 +146,6 @@ rm tests/ui/process/nofile-limit.rs # TODO some AArch64 linking issue rm tests/ui/stdio-is-blocking.rs # really slow with unoptimized libstd -# rustc bugs -# ========== -# https://github.com/rust-lang/rust/pull/116447#issuecomment-1790451463 -rm tests/ui/coroutine/gen_block_*.rs - cp ../dist/bin/rustdoc-clif ../dist/bin/rustdoc # some tests expect bin/rustdoc to exist # prevent $(RUSTDOC) from picking up the sysroot built by x.py. It conflicts with the one used by From 2c233863443201117b711bab0e0bf6966cd221f3 Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 24 Nov 2023 00:49:02 +0300 Subject: [PATCH 57/93] rustc: Make `def_kind` mandatory for all `DefId`s --- compiler/rustc_metadata/src/rmeta/decoder.rs | 15 ++++++--------- .../src/rmeta/decoder/cstore_impl.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 19 ++++++++++++------- compiler/rustc_metadata/src/rmeta/mod.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 18 +++++++----------- compiler/rustc_middle/src/hir/mod.rs | 2 +- compiler/rustc_middle/src/query/mod.rs | 2 +- compiler/rustc_middle/src/query/plumbing.rs | 17 ----------------- compiler/rustc_privacy/src/lib.rs | 2 +- compiler/rustc_query_impl/src/plumbing.rs | 4 ++-- compiler/rustc_ty_utils/src/assoc.rs | 4 ++-- .../clippy/clippy_lints/src/unused_async.rs | 2 +- .../clippy_lints/src/useless_conversion.rs | 3 +-- 13 files changed, 36 insertions(+), 56 deletions(-) diff --git a/compiler/rustc_metadata/src/rmeta/decoder.rs b/compiler/rustc_metadata/src/rmeta/decoder.rs index 333dc8ec9111..5725a759fef8 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder.rs @@ -850,7 +850,7 @@ impl MetadataBlob { ) -> io::Result<()> { let root = blob.get_root(); - let def_kind = root.tables.opt_def_kind.get(blob, item).unwrap(); + let def_kind = root.tables.def_kind.get(blob, item).unwrap(); let def_key = root.tables.def_keys.get(blob, item).unwrap().decode(blob); let def_name = if item == CRATE_DEF_INDEX { rustc_span::symbol::kw::Crate @@ -1001,14 +1001,11 @@ impl<'a, 'tcx> CrateMetadataRef<'a> { } fn def_kind(self, item_id: DefIndex) -> DefKind { - self.root.tables.opt_def_kind.get(self, item_id).unwrap_or_else(|| { - bug!( - "CrateMetadata::def_kind({:?}): id not found, in crate {:?} with number {}", - item_id, - self.root.name(), - self.cnum, - ) - }) + self.root + .tables + .def_kind + .get(self, item_id) + .unwrap_or_else(|| self.missing("def_kind", item_id)) } fn get_span(self, index: DefIndex, sess: &Session) -> Span { diff --git a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs index 0250c92dd78b..f6cd013d2ef1 100644 --- a/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs +++ b/compiler/rustc_metadata/src/rmeta/decoder/cstore_impl.rs @@ -231,7 +231,7 @@ provide! { tcx, def_id, other, cdata, lookup_deprecation_entry => { table } params_in_repr => { table } unused_generic_params => { cdata.root.tables.unused_generic_params.get(cdata, def_id.index) } - opt_def_kind => { table_direct } + def_kind => { cdata.def_kind(def_id.index) } impl_parent => { table } impl_polarity => { table_direct } defaultness => { table_direct } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 19add1ef1acf..562eaf213d22 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1354,9 +1354,8 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { for local_id in tcx.iter_local_def_id() { let def_id = local_id.to_def_id(); - let def_kind = tcx.opt_def_kind(local_id); - let Some(def_kind) = def_kind else { continue }; - self.tables.opt_def_kind.set_some(def_id.index, def_kind); + let def_kind = tcx.def_kind(local_id); + self.tables.def_kind.set_some(def_id.index, def_kind); if should_encode_span(def_kind) { let def_span = tcx.def_span(local_id); record!(self.tables.def_span[def_id] <- def_span); @@ -1393,7 +1392,13 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { if should_encode_fn_sig(def_kind) { record!(self.tables.fn_sig[def_id] <- tcx.fn_sig(def_id)); } - if should_encode_generics(def_kind) { + // FIXME: Some anonymous constants produced by `#[rustc_legacy_const_generics]` + // do not have corresponding HIR nodes, so some queries usually making sense for + // anonymous constants will not work on them and panic. It's not clear whether it + // can cause any observable issues or not. + let anon_const_without_hir = def_kind == DefKind::AnonConst + && tcx.hir().find(tcx.local_def_id_to_hir_id(local_id)).is_none(); + if should_encode_generics(def_kind) && !anon_const_without_hir { let g = tcx.generics_of(def_id); record!(self.tables.generics_of[def_id] <- g); record!(self.tables.explicit_predicates_of[def_id] <- self.tcx.explicit_predicates_of(def_id)); @@ -1407,7 +1412,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } } } - if should_encode_type(tcx, local_id, def_kind) { + if should_encode_type(tcx, local_id, def_kind) && !anon_const_without_hir { record!(self.tables.type_of[def_id] <- self.tcx.type_of(def_id)); } if should_encode_constness(def_kind) { @@ -1785,7 +1790,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.tables.proc_macro_quoted_spans.set_some(i, span); } - self.tables.opt_def_kind.set_some(LOCAL_CRATE.as_def_id().index, DefKind::Mod); + self.tables.def_kind.set_some(LOCAL_CRATE.as_def_id().index, DefKind::Mod); record!(self.tables.def_span[LOCAL_CRATE.as_def_id()] <- tcx.def_span(LOCAL_CRATE.as_def_id())); self.encode_attrs(LOCAL_CRATE.as_def_id().expect_local()); let vis = tcx.local_visibility(CRATE_DEF_ID).map_id(|def_id| def_id.local_def_index); @@ -1833,7 +1838,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { def_key.disambiguated_data.data = DefPathData::MacroNs(name); let def_id = id.to_def_id(); - self.tables.opt_def_kind.set_some(def_id.index, DefKind::Macro(macro_kind)); + self.tables.def_kind.set_some(def_id.index, DefKind::Macro(macro_kind)); self.tables.proc_macro.set_some(def_id.index, macro_kind); self.encode_attrs(id); record!(self.tables.def_keys[def_id] <- def_key); diff --git a/compiler/rustc_metadata/src/rmeta/mod.rs b/compiler/rustc_metadata/src/rmeta/mod.rs index 145db4b2ed6a..ea8ef50460e5 100644 --- a/compiler/rustc_metadata/src/rmeta/mod.rs +++ b/compiler/rustc_metadata/src/rmeta/mod.rs @@ -405,7 +405,7 @@ define_tables! { // so we can take their names, visibilities etc from other encoded tables. module_children_non_reexports: Table>, associated_item_or_field_def_ids: Table>, - opt_def_kind: Table, + def_kind: Table, visibility: Table>>, def_span: Table>, def_ident_span: Table>, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index 9d8168382d20..c1c2ac22bd39 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -174,21 +174,18 @@ impl<'hir> Map<'hir> { } /// Do not call this function directly. The query should be called. - pub(super) fn opt_def_kind(self, local_def_id: LocalDefId) -> Option { + pub(super) fn def_kind(self, local_def_id: LocalDefId) -> DefKind { let hir_id = self.local_def_id_to_hir_id(local_def_id); let node = match self.find(hir_id) { Some(node) => node, None => match self.def_key(local_def_id).disambiguated_data.data { - // FIXME: Some anonymous constants do not have corresponding HIR nodes, - // so many local queries will panic on their def ids. `None` is currently - // returned here instead of `DefKind::{Anon,Inline}Const` to avoid such panics. - // Ideally all def ids should have `DefKind`s, we need to create the missing - // HIR nodes or feed relevant query results to achieve that. - DefPathData::AnonConst => return None, + // FIXME: Some anonymous constants produced by `#[rustc_legacy_const_generics]` + // do not have corresponding HIR nodes, but they are still anonymous constants. + DefPathData::AnonConst => return DefKind::AnonConst, _ => bug!("no HIR node for def id {local_def_id:?}"), }, }; - let def_kind = match node { + match node { Node::Item(item) => match item.kind { ItemKind::Static(_, mt, _) => DefKind::Static(mt), ItemKind::Const(..) => DefKind::Const, @@ -266,8 +263,7 @@ impl<'hir> Map<'hir> { self.span(hir_id), "unexpected node with def id {local_def_id:?}: {node:?}" ), - }; - Some(def_kind) + } } /// Finds the id of the parent node to this one. @@ -895,7 +891,7 @@ impl<'hir> Map<'hir> { #[inline] fn opt_ident(self, id: HirId) -> Option { - match self.get(id) { + match self.find(id)? { Node::Pat(&Pat { kind: PatKind::Binding(_, _, ident, _), .. }) => Some(ident), // A `Ctor` doesn't have an identifier itself, but its parent // struct/variant does. Compare with `hir::Map::opt_span`. diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index f28ec771169f..af7a2efe35a8 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -202,7 +202,7 @@ pub fn provide(providers: &mut Providers) { span_bug!(hir.span(hir_id), "fn_arg_names: unexpected item {:?}", def_id); } }; - providers.opt_def_kind = |tcx, def_id| tcx.hir().opt_def_kind(def_id); + providers.def_kind = |tcx, def_id| tcx.hir().def_kind(def_id); providers.all_local_trait_impls = |tcx, ()| &tcx.resolutions(()).trait_impls; providers.expn_that_defined = |tcx, id| tcx.resolutions(()).expn_that_defined.get(&id).copied().unwrap_or(ExpnId::root()); diff --git a/compiler/rustc_middle/src/query/mod.rs b/compiler/rustc_middle/src/query/mod.rs index 22f3d733dc3e..29decd0f050e 100644 --- a/compiler/rustc_middle/src/query/mod.rs +++ b/compiler/rustc_middle/src/query/mod.rs @@ -1151,7 +1151,7 @@ rustc_queries! { cache_on_disk_if { true } } - query opt_def_kind(def_id: DefId) -> Option { + query def_kind(def_id: DefId) -> DefKind { desc { |tcx| "looking up definition kind of `{}`", tcx.def_path_str(def_id) } cache_on_disk_if { def_id.is_local() } separate_provide_extern diff --git a/compiler/rustc_middle/src/query/plumbing.rs b/compiler/rustc_middle/src/query/plumbing.rs index ac3538f181ee..9a6eba896553 100644 --- a/compiler/rustc_middle/src/query/plumbing.rs +++ b/compiler/rustc_middle/src/query/plumbing.rs @@ -12,7 +12,6 @@ use measureme::StringId; use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sync::AtomicU64; use rustc_data_structures::sync::WorkerLocal; -use rustc_hir::def::DefKind; use rustc_hir::def_id::{DefId, LocalDefId}; use rustc_hir::hir_id::OwnerId; use rustc_query_system::dep_graph::DepNodeIndex; @@ -668,21 +667,5 @@ mod sealed { pub use sealed::IntoQueryParam; -impl<'tcx> TyCtxt<'tcx> { - pub fn def_kind(self, def_id: impl IntoQueryParam) -> DefKind { - let def_id = def_id.into_query_param(); - self.opt_def_kind(def_id) - .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id)) - } -} - -impl<'tcx> TyCtxtAt<'tcx> { - pub fn def_kind(self, def_id: impl IntoQueryParam) -> DefKind { - let def_id = def_id.into_query_param(); - self.opt_def_kind(def_id) - .unwrap_or_else(|| bug!("def_kind: unsupported node: {:?}", def_id)) - } -} - #[derive(Copy, Clone, Debug, HashStable)] pub struct CyclePlaceholder(pub ErrorGuaranteed); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 4324afe42b38..d46bc9466f65 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -500,7 +500,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { } let macro_module_def_id = self.tcx.local_parent(local_def_id); - if self.tcx.opt_def_kind(macro_module_def_id) != Some(DefKind::Mod) { + if self.tcx.def_kind(macro_module_def_id) != DefKind::Mod { // The macro's parent doesn't correspond to a `mod`, return early (#63164, #65252). return; } diff --git a/compiler/rustc_query_impl/src/plumbing.rs b/compiler/rustc_query_impl/src/plumbing.rs index a290bd10bea0..9faf63f00e27 100644 --- a/compiler/rustc_query_impl/src/plumbing.rs +++ b/compiler/rustc_query_impl/src/plumbing.rs @@ -325,11 +325,11 @@ pub(crate) fn create_query_frame< Some(key.default_span(tcx)) }; let def_id = key.key_as_def_id(); - let def_kind = if kind == dep_graph::dep_kinds::opt_def_kind || with_no_queries() { + let def_kind = if kind == dep_graph::dep_kinds::def_kind || with_no_queries() { // Try to avoid infinite recursion. None } else { - def_id.and_then(|def_id| def_id.as_local()).and_then(|def_id| tcx.opt_def_kind(def_id)) + def_id.and_then(|def_id| def_id.as_local()).map(|def_id| tcx.def_kind(def_id)) }; let hash = || { tcx.with_stable_hashing_context(|mut hcx| { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index e29fed37f85b..a1ebf386e74e 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -259,7 +259,7 @@ fn associated_type_for_impl_trait_in_trait( let local_def_id = trait_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); - trait_assoc_ty.opt_def_kind(Some(DefKind::AssocTy)); + trait_assoc_ty.def_kind(DefKind::AssocTy); // There's no HIR associated with this new synthesized `def_id`, so feed // `opt_local_def_id_to_hir_id` with `None`. @@ -362,7 +362,7 @@ fn associated_type_for_impl_trait_in_impl( let local_def_id = impl_assoc_ty.def_id(); let def_id = local_def_id.to_def_id(); - impl_assoc_ty.opt_def_kind(Some(DefKind::AssocTy)); + impl_assoc_ty.def_kind(DefKind::AssocTy); // There's no HIR associated with this new synthesized `def_id`, so feed // `opt_local_def_id_to_hir_id` with `None`. diff --git a/src/tools/clippy/clippy_lints/src/unused_async.rs b/src/tools/clippy/clippy_lints/src/unused_async.rs index aea72c798be7..780ece3677df 100644 --- a/src/tools/clippy/clippy_lints/src/unused_async.rs +++ b/src/tools/clippy/clippy_lints/src/unused_async.rs @@ -148,7 +148,7 @@ impl<'tcx> LateLintPass<'tcx> for UnusedAsync { // statements, so don't lint at all if there are any such paths. if let Some(def_id) = path.res.opt_def_id() && let Some(local_def_id) = def_id.as_local() - && let Some(DefKind::Fn) = cx.tcx.opt_def_kind(def_id) + && cx.tcx.def_kind(def_id) == DefKind::Fn && cx.tcx.asyncness(def_id).is_async() && !is_node_func_call(cx.tcx.hir().get_parent(hir_id), path.span) { diff --git a/src/tools/clippy/clippy_lints/src/useless_conversion.rs b/src/tools/clippy/clippy_lints/src/useless_conversion.rs index 52327b82e849..7aed1d6e30b4 100644 --- a/src/tools/clippy/clippy_lints/src/useless_conversion.rs +++ b/src/tools/clippy/clippy_lints/src/useless_conversion.rs @@ -4,7 +4,6 @@ use clippy_utils::sugg::Sugg; use clippy_utils::ty::{is_copy, is_type_diagnostic_item, same_type_and_consts}; use clippy_utils::{get_parent_expr, is_trait_method, is_ty_alias, path_to_local}; use rustc_errors::Applicability; -use rustc_hir::def::DefKind; use rustc_hir::def_id::DefId; use rustc_hir::{BindingAnnotation, Expr, ExprKind, HirId, MatchSource, Node, PatKind}; use rustc_infer::infer::TyCtxtInferExt; @@ -208,7 +207,7 @@ impl<'tcx> LateLintPass<'tcx> for UselessConversion { && let Some(did) = cx.qpath_res(qpath, recv.hir_id).opt_def_id() // make sure that the path indeed points to a fn-like item, so that // `fn_sig` does not ICE. (see #11065) - && cx.tcx.opt_def_kind(did).is_some_and(DefKind::is_fn_like) => + && cx.tcx.def_kind(did).is_fn_like() => { Some(( did, From 63b2f55e83c7fc513eb049746fc4658848b47a4e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 25 Nov 2023 17:17:25 +0000 Subject: [PATCH 58/93] is_{some,ok}_and for rustdoc --- src/librustdoc/clean/types.rs | 4 ++-- src/librustdoc/clean/utils.rs | 5 ++--- src/librustdoc/config.rs | 2 +- src/librustdoc/formats/cache.rs | 8 ++++---- src/librustdoc/html/render/mod.rs | 5 ++--- src/librustdoc/passes/collect_trait_impls.rs | 2 +- 6 files changed, 12 insertions(+), 14 deletions(-) diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ded256fd75c5..ddbbce865488 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -498,7 +498,7 @@ impl Item { } pub(crate) fn is_crate(&self) -> bool { - self.is_mod() && self.def_id().map_or(false, |did| did.is_crate_root()) + self.is_mod() && self.def_id().is_some_and(|did| did.is_crate_root()) } pub(crate) fn is_mod(&self) -> bool { self.type_() == ItemType::Module @@ -2487,7 +2487,7 @@ impl Import { } pub(crate) fn imported_item_is_doc_hidden(&self, tcx: TyCtxt<'_>) -> bool { - self.source.did.map_or(false, |did| tcx.is_doc_hidden(did)) + self.source.did.is_some_and(|did| tcx.is_doc_hidden(did)) } } diff --git a/src/librustdoc/clean/utils.rs b/src/librustdoc/clean/utils.rs index eb47ff94d2ee..c22ad43e0499 100644 --- a/src/librustdoc/clean/utils.rs +++ b/src/librustdoc/clean/utils.rs @@ -573,9 +573,8 @@ pub(crate) fn find_nearest_parent_module(tcx: TyCtxt<'_>, def_id: DefId) -> Opti /// This function exists because it runs on `hir::Attributes` whereas the other is a /// `clean::Attributes` method. pub(crate) fn has_doc_flag(tcx: TyCtxt<'_>, did: DefId, flag: Symbol) -> bool { - tcx.get_attrs(did, sym::doc).any(|attr| { - attr.meta_item_list().map_or(false, |l| rustc_attr::list_contains_name(&l, flag)) - }) + tcx.get_attrs(did, sym::doc) + .any(|attr| attr.meta_item_list().is_some_and(|l| rustc_attr::list_contains_name(&l, flag))) } /// A link to `doc.rust-lang.org` that includes the channel name. Use this instead of manual links diff --git a/src/librustdoc/config.rs b/src/librustdoc/config.rs index 99aa979027f4..8e8b7ab346b3 100644 --- a/src/librustdoc/config.rs +++ b/src/librustdoc/config.rs @@ -798,7 +798,7 @@ impl Options { /// Returns `true` if the file given as `self.input` is a Markdown file. pub(crate) fn markdown_input(&self) -> bool { - self.input.extension().map_or(false, |e| e == "md" || e == "markdown") + self.input.extension().is_some_and(|e| e == "md" || e == "markdown") } } diff --git a/src/librustdoc/formats/cache.rs b/src/librustdoc/formats/cache.rs index 9b1b6899751e..9802097ea290 100644 --- a/src/librustdoc/formats/cache.rs +++ b/src/librustdoc/formats/cache.rs @@ -234,10 +234,10 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { && (self.cache.masked_crates.contains(&item.item_id.krate()) || i.trait_ .as_ref() - .map_or(false, |t| is_from_private_dep(self.tcx, self.cache, t.def_id())) + .is_some_and(|t| is_from_private_dep(self.tcx, self.cache, t.def_id())) || i.for_ .def_id(self.cache) - .map_or(false, |d| is_from_private_dep(self.tcx, self.cache, d))) + .is_some_and(|d| is_from_private_dep(self.tcx, self.cache, d))) { return None; } @@ -279,7 +279,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { .cache .parent_stack .last() - .map_or(false, |parent| parent.is_trait_impl()) => + .is_some_and(|parent| parent.is_trait_impl()) => { // skip associated items in trait impls ((None, None), false) @@ -341,7 +341,7 @@ impl<'a, 'tcx> DocFolder for CacheBuilder<'a, 'tcx> { // A crate has a module at its root, containing all items, // which should not be indexed. The crate-item itself is // inserted later on when serializing the search-index. - if item.item_id.as_def_id().map_or(false, |idx| !idx.is_crate_root()) + if item.item_id.as_def_id().is_some_and(|idx| !idx.is_crate_root()) && let ty = item.type_() && (ty != ItemType::StructField || u16::from_str_radix(s.as_str(), 10).is_err()) diff --git a/src/librustdoc/html/render/mod.rs b/src/librustdoc/html/render/mod.rs index 8b3cd9ca6fc0..ff5c761208b4 100644 --- a/src/librustdoc/html/render/mod.rs +++ b/src/librustdoc/html/render/mod.rs @@ -1381,8 +1381,7 @@ pub(crate) fn notable_traits_button(ty: &clean::Type, cx: &mut Context<'_>) -> O if let Some(trait_) = &impl_.trait_ { let trait_did = trait_.def_id(); - if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx())) - { + if cx.cache().traits.get(&trait_did).is_some_and(|t| t.is_notable_trait(cx.tcx())) { has_notable_trait = true; } } @@ -1417,7 +1416,7 @@ fn notable_traits_decl(ty: &clean::Type, cx: &Context<'_>) -> (String, String) { if let Some(trait_) = &impl_.trait_ { let trait_did = trait_.def_id(); - if cx.cache().traits.get(&trait_did).map_or(false, |t| t.is_notable_trait(cx.tcx())) { + if cx.cache().traits.get(&trait_did).is_some_and(|t| t.is_notable_trait(cx.tcx())) { if out.is_empty() { write!( &mut out, diff --git a/src/librustdoc/passes/collect_trait_impls.rs b/src/librustdoc/passes/collect_trait_impls.rs index b60d7d4c718f..b6f73d3fdcda 100644 --- a/src/librustdoc/passes/collect_trait_impls.rs +++ b/src/librustdoc/passes/collect_trait_impls.rs @@ -198,7 +198,7 @@ pub(crate) fn collect_trait_impls(mut krate: Crate, cx: &mut DocContext<'_>) -> cleaner.keep_impl( for_, trait_.as_ref().map(|t| t.def_id()) == tcx.lang_items().deref_trait(), - ) || trait_.as_ref().map_or(false, |t| cleaner.keep_impl_with_def_id(t.def_id().into())) + ) || trait_.as_ref().is_some_and(|t| cleaner.keep_impl_with_def_id(t.def_id().into())) || kind.is_blanket() } else { true From 884679ff6325e0ba51f8b2ed246514ba36900dc5 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 25 Nov 2023 10:39:45 -0700 Subject: [PATCH 59/93] rustdoc-search: clean up some DOM code --- src/librustdoc/html/static/js/search.js | 16 +++++----------- 1 file changed, 5 insertions(+), 11 deletions(-) diff --git a/src/librustdoc/html/static/js/search.js b/src/librustdoc/html/static/js/search.js index 0bb56cd97101..979aebdb7bed 100644 --- a/src/librustdoc/html/static/js/search.js +++ b/src/librustdoc/html/static/js/search.js @@ -2424,10 +2424,7 @@ function initSearch(rawSearchIndex) { * @param {boolean} display - True if this is the active tab */ function addTab(array, query, display) { - let extraClass = ""; - if (display === true) { - extraClass = " active"; - } + const extraClass = display ? " active" : ""; const output = document.createElement("div"); let length = 0; @@ -2669,13 +2666,9 @@ ${item.displayPath}${name}\ /** * Perform a search based on the current state of the search input element * and display the results. - * @param {Event} [e] - The event that triggered this search, if any * @param {boolean} [forced] */ - function search(e, forced) { - if (e) { - e.preventDefault(); - } + function search(forced) { const query = parseQuery(searchState.input.value.trim()); let filterCrates = getFilterCrates(); @@ -3212,7 +3205,8 @@ ${item.displayPath}${name}\ // popping a state (Firefox), which is why search() is // called both here and at the end of the startSearch() // function. - search(e); + e.preventDefault(); + search(); } else { searchState.input.value = ""; // When browsing back from search results the main page @@ -3247,7 +3241,7 @@ ${item.displayPath}${name}\ // before paste back the previous search, you get the old search results without // the filter. To prevent this, we need to remove the previous results. currentResults = null; - search(undefined, true); + search(true); } /** From 1279f70bf43c7f807abdedf818ca9680f0e9676f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 25 Nov 2023 17:40:52 +0000 Subject: [PATCH 60/93] Don't ICE when encountering placeholders in implied bounds computation --- .../query/type_op/implied_outlives_bounds.rs | 6 ++++-- .../in-trait/placeholder-implied-bounds.rs | 14 ++++++++++++++ 2 files changed, 18 insertions(+), 2 deletions(-) create mode 100644 tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs diff --git a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs index 94d6b15fe437..56844f39478f 100644 --- a/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs +++ b/compiler/rustc_trait_selection/src/traits/query/type_op/implied_outlives_bounds.rs @@ -207,8 +207,10 @@ fn implied_bounds_from_components<'tcx>( Component::Region(r) => Some(OutlivesBound::RegionSubRegion(sub_region, r)), Component::Param(p) => Some(OutlivesBound::RegionSubParam(sub_region, p)), Component::Alias(p) => Some(OutlivesBound::RegionSubAlias(sub_region, p)), - Component::Placeholder(_) => { - unimplemented!("Shouldn't expect a placeholder type in implied bounds (yet)") + Component::Placeholder(_p) => { + // FIXME(non_lifetime_binders): Placeholders don't currently + // imply anything for outlives, though they could easily. + None } Component::EscapingAlias(_) => // If the projection has escaping regions, don't diff --git a/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs b/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs new file mode 100644 index 000000000000..33d3487030e4 --- /dev/null +++ b/tests/ui/impl-trait/in-trait/placeholder-implied-bounds.rs @@ -0,0 +1,14 @@ +// check-pass + +pub fn main() {} + +pub trait Iced { + fn get(&self) -> &impl Sized; +} + +/// Impl causes ICE +impl Iced for () { + fn get(&self) -> &impl Sized { + &() + } +} From a992defc8b0d7937d0422003984b7b5d3e5f472e Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 5 Oct 2023 09:39:33 +0000 Subject: [PATCH 61/93] Remove mir::Const::from_anon_const --- compiler/rustc_middle/src/mir/consts.rs | 102 +------------------ compiler/rustc_middle/src/ty/consts.rs | 4 + compiler/rustc_mir_build/src/thir/cx/expr.rs | 26 ++++- 3 files changed, 29 insertions(+), 103 deletions(-) diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index 84a9ab4013be..fa7fa8e8c74d 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -1,17 +1,16 @@ use std::fmt::{self, Debug, Display, Formatter}; use rustc_hir; -use rustc_hir::def_id::{DefId, LocalDefId}; -use rustc_hir::{self as hir}; +use rustc_hir::def_id::DefId; use rustc_session::RemapFileNameExt; use rustc_span::Span; use rustc_target::abi::{HasDataLayout, Size}; use crate::mir::interpret::{alloc_range, AllocId, ConstAllocation, ErrorHandled, Scalar}; use crate::mir::{pretty_print_const_value, Promoted}; +use crate::ty::GenericArgsRef; use crate::ty::ScalarInt; -use crate::ty::{self, print::pretty_print_const, List, Ty, TyCtxt}; -use crate::ty::{GenericArgs, GenericArgsRef}; +use crate::ty::{self, print::pretty_print_const, Ty, TyCtxt}; /////////////////////////////////////////////////////////////////////////// /// Evaluated Constants @@ -399,101 +398,6 @@ impl<'tcx> Const<'tcx> { Self::Val(val, ty) } - /// Literals are converted to `Const::Val`, const generic parameters are eagerly - /// converted to a constant, everything else becomes `Unevaluated`. - #[instrument(skip(tcx), level = "debug", ret)] - pub fn from_anon_const( - tcx: TyCtxt<'tcx>, - def: LocalDefId, - param_env: ty::ParamEnv<'tcx>, - ) -> Self { - let body_id = match tcx.hir().get_by_def_id(def) { - hir::Node::AnonConst(ac) => ac.body, - _ => { - span_bug!(tcx.def_span(def), "from_anon_const can only process anonymous constants") - } - }; - - let expr = &tcx.hir().body(body_id).value; - debug!(?expr); - - // Unwrap a block, so that e.g. `{ P }` is recognised as a parameter. Const arguments - // currently have to be wrapped in curly brackets, so it's necessary to special-case. - let expr = match &expr.kind { - hir::ExprKind::Block(block, _) if block.stmts.is_empty() && block.expr.is_some() => { - block.expr.as_ref().unwrap() - } - _ => expr, - }; - debug!("expr.kind: {:?}", expr.kind); - - let ty = tcx.type_of(def).instantiate_identity(); - debug!(?ty); - - // FIXME(const_generics): We currently have to special case parameters because `min_const_generics` - // does not provide the parents generics to anonymous constants. We still allow generic const - // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to - // ever try to substitute the generic parameters in their bodies. - // - // While this doesn't happen as these constants are always used as `ty::ConstKind::Param`, it does - // cause issues if we were to remove that special-case and try to evaluate the constant instead. - use hir::{def::DefKind::ConstParam, def::Res, ExprKind, Path, QPath}; - match expr.kind { - ExprKind::Path(QPath::Resolved(_, &Path { res: Res::Def(ConstParam, def_id), .. })) => { - // Find the name and index of the const parameter by indexing the generics of - // the parent item and construct a `ParamConst`. - let item_def_id = tcx.parent(def_id); - let generics = tcx.generics_of(item_def_id); - let index = generics.param_def_id_to_index[&def_id]; - let name = tcx.item_name(def_id); - let ty_const = ty::Const::new_param(tcx, ty::ParamConst::new(index, name), ty); - debug!(?ty_const); - - return Self::Ty(ty_const); - } - _ => {} - } - - let hir_id = tcx.hir().local_def_id_to_hir_id(def); - let parent_args = if let Some(parent_hir_id) = tcx.hir().opt_parent_id(hir_id) - && let Some(parent_did) = parent_hir_id.as_owner() - { - GenericArgs::identity_for_item(tcx, parent_did) - } else { - List::empty() - }; - debug!(?parent_args); - - let did = def.to_def_id(); - let child_args = GenericArgs::identity_for_item(tcx, did); - let args = tcx.mk_args_from_iter(parent_args.into_iter().chain(child_args.into_iter())); - debug!(?args); - - let span = tcx.def_span(def); - let uneval = UnevaluatedConst::new(did, args); - debug!(?span, ?param_env); - - match tcx.const_eval_resolve(param_env, uneval, Some(span)) { - Ok(val) => { - debug!("evaluated const value"); - Self::Val(val, ty) - } - Err(_) => { - debug!("error encountered during evaluation"); - // Error was handled in `const_eval_resolve`. Here we just create a - // new unevaluated const and error hard later in codegen - Self::Unevaluated( - UnevaluatedConst { - def: did, - args: GenericArgs::identity_for_item(tcx, did), - promoted: None, - }, - ty, - ) - } - } - } - pub fn from_ty_const(c: ty::Const<'tcx>, tcx: TyCtxt<'tcx>) -> Self { match c.kind() { ty::ConstKind::Value(valtree) => { diff --git a/compiler/rustc_middle/src/ty/consts.rs b/compiler/rustc_middle/src/ty/consts.rs index 0f5817c78e0a..d0a1c9432922 100644 --- a/compiler/rustc_middle/src/ty/consts.rs +++ b/compiler/rustc_middle/src/ty/consts.rs @@ -216,6 +216,10 @@ impl<'tcx> Const<'tcx> { } } + // FIXME(const_generics): We currently have to special case parameters because `min_const_generics` + // does not provide the parents generics to anonymous constants. We still allow generic const + // parameters by themselves however, e.g. `N`. These constants would cause an ICE if we were to + // ever try to substitute the generic parameters in their bodies. match expr.kind { hir::ExprKind::Path(hir::QPath::Resolved( _, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index 6541b4f6a3e0..e01ee45180f5 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -642,15 +642,33 @@ impl<'tcx> Cx<'tcx> { } } hir::InlineAsmOperand::Const { ref anon_const } => { - let value = - mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env); + let value = mir::Const::Unevaluated( + mir::UnevaluatedConst { + def: anon_const.def_id.to_def_id(), + args: GenericArgs::identity_for_item( + self.tcx, + anon_const.def_id, + ), + promoted: None, + }, + tcx.type_of(anon_const.def_id).instantiate_identity(), + ); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::Const { value, span } } hir::InlineAsmOperand::SymFn { ref anon_const } => { - let value = - mir::Const::from_anon_const(tcx, anon_const.def_id, self.param_env); + let value = mir::Const::Unevaluated( + mir::UnevaluatedConst { + def: anon_const.def_id.to_def_id(), + args: GenericArgs::identity_for_item( + self.tcx, + anon_const.def_id, + ), + promoted: None, + }, + tcx.type_of(anon_const.def_id).instantiate_identity(), + ); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::SymFn { value, span } From 82f23d56b758d87e5eee642946ad8a422e6542ba Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 5 Oct 2023 09:43:55 +0000 Subject: [PATCH 62/93] make sure we still eagerly emit errors --- compiler/rustc_mir_build/src/thir/cx/expr.rs | 6 ++++-- tests/ui/asm/const-error.rs | 15 +++++++++++++++ tests/ui/asm/const-error.stderr | 9 +++++++++ 3 files changed, 28 insertions(+), 2 deletions(-) create mode 100644 tests/ui/asm/const-error.rs create mode 100644 tests/ui/asm/const-error.stderr diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index e01ee45180f5..b07ffe7293ba 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -652,7 +652,8 @@ impl<'tcx> Cx<'tcx> { promoted: None, }, tcx.type_of(anon_const.def_id).instantiate_identity(), - ); + ) + .normalize(tcx, self.param_env); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::Const { value, span } @@ -668,7 +669,8 @@ impl<'tcx> Cx<'tcx> { promoted: None, }, tcx.type_of(anon_const.def_id).instantiate_identity(), - ); + ) + .normalize(tcx, self.param_env); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::SymFn { value, span } diff --git a/tests/ui/asm/const-error.rs b/tests/ui/asm/const-error.rs new file mode 100644 index 000000000000..4e14becf74be --- /dev/null +++ b/tests/ui/asm/const-error.rs @@ -0,0 +1,15 @@ +// only-x86_64 +// needs-asm-support + +#![feature(asm_const)] + +// Test to make sure that we emit const errors eagerly for inline asm + +use std::arch::asm; + +fn test() { + unsafe { asm!("/* {} */", const 1 / 0); } + //~^ ERROR evaluation of +} + +fn main() {} diff --git a/tests/ui/asm/const-error.stderr b/tests/ui/asm/const-error.stderr new file mode 100644 index 000000000000..fe3118321772 --- /dev/null +++ b/tests/ui/asm/const-error.stderr @@ -0,0 +1,9 @@ +error[E0080]: evaluation of `test::::{constant#0}` failed + --> $DIR/const-error.rs:11:37 + | +LL | unsafe { asm!("/* {} */", const 1 / 0); } + | ^^^^^ attempt to divide `1_i32` by zero + +error: aborting due to 1 previous error + +For more information about this error, try `rustc --explain E0080`. From 8bf9c18914b8c474f15da39fa6ce3e2522d5baa5 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Fri, 17 Nov 2023 23:49:07 +0000 Subject: [PATCH 63/93] Review comment --- compiler/rustc_middle/src/mir/consts.rs | 11 ++++++++ compiler/rustc_mir_build/src/thir/cx/expr.rs | 28 ++++++-------------- 2 files changed, 19 insertions(+), 20 deletions(-) diff --git a/compiler/rustc_middle/src/mir/consts.rs b/compiler/rustc_middle/src/mir/consts.rs index fa7fa8e8c74d..d38df1b72010 100644 --- a/compiler/rustc_middle/src/mir/consts.rs +++ b/compiler/rustc_middle/src/mir/consts.rs @@ -219,6 +219,17 @@ pub enum Const<'tcx> { } impl<'tcx> Const<'tcx> { + pub fn identity_unevaluated(tcx: TyCtxt<'tcx>, def_id: DefId) -> ty::EarlyBinder> { + ty::EarlyBinder::bind(Const::Unevaluated( + UnevaluatedConst { + def: def_id, + args: ty::GenericArgs::identity_for_item(tcx, def_id), + promoted: None, + }, + tcx.type_of(def_id).skip_binder(), + )) + } + #[inline(always)] pub fn ty(&self) -> Ty<'tcx> { match self { diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index b07ffe7293ba..d3af1b7745ec 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -642,34 +642,22 @@ impl<'tcx> Cx<'tcx> { } } hir::InlineAsmOperand::Const { ref anon_const } => { - let value = mir::Const::Unevaluated( - mir::UnevaluatedConst { - def: anon_const.def_id.to_def_id(), - args: GenericArgs::identity_for_item( - self.tcx, - anon_const.def_id, - ), - promoted: None, - }, - tcx.type_of(anon_const.def_id).instantiate_identity(), + let value = mir::Const::identity_unevaluated( + tcx, + anon_const.def_id.to_def_id(), ) + .instantiate_identity() .normalize(tcx, self.param_env); let span = tcx.def_span(anon_const.def_id); InlineAsmOperand::Const { value, span } } hir::InlineAsmOperand::SymFn { ref anon_const } => { - let value = mir::Const::Unevaluated( - mir::UnevaluatedConst { - def: anon_const.def_id.to_def_id(), - args: GenericArgs::identity_for_item( - self.tcx, - anon_const.def_id, - ), - promoted: None, - }, - tcx.type_of(anon_const.def_id).instantiate_identity(), + let value = mir::Const::identity_unevaluated( + tcx, + anon_const.def_id.to_def_id(), ) + .instantiate_identity() .normalize(tcx, self.param_env); let span = tcx.def_span(anon_const.def_id); From fa7633dda10845180dcb0e5aadf7faf013391cc2 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 23 Nov 2023 06:01:35 +0000 Subject: [PATCH 64/93] Remove HirId from QPath::LangItem --- compiler/rustc_ast_lowering/src/expr.rs | 50 ++++--------------- compiler/rustc_ast_lowering/src/lib.rs | 11 ++-- .../src/diagnostics/conflict_errors.rs | 12 ++--- compiler/rustc_hir/src/hir.rs | 8 +-- .../rustc_hir_analysis/src/astconv/mod.rs | 2 +- compiler/rustc_hir_pretty/src/lib.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 7 ++- .../rustc_hir_typeck/src/fn_ctxt/_impl.rs | 9 +++- .../rustc_hir_typeck/src/fn_ctxt/checks.rs | 4 +- .../infer/error_reporting/need_type_info.rs | 2 +- compiler/rustc_middle/src/traits/mod.rs | 2 +- .../src/traits/error_reporting/suggestions.rs | 3 +- 12 files changed, 41 insertions(+), 71 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/expr.rs b/compiler/rustc_ast_lowering/src/expr.rs index d44c585a07d3..6f2f9787e772 100644 --- a/compiler/rustc_ast_lowering/src/expr.rs +++ b/compiler/rustc_ast_lowering/src/expr.rs @@ -560,7 +560,7 @@ impl<'hir> LoweringContext<'_, 'hir> { expr: &'hir hir::Expr<'hir>, overall_span: Span, ) -> &'hir hir::Expr<'hir> { - let constructor = self.arena.alloc(self.expr_lang_item_path(method_span, lang_item, None)); + let constructor = self.arena.alloc(self.expr_lang_item_path(method_span, lang_item)); self.expr_call(overall_span, constructor, std::slice::from_ref(expr)) } @@ -614,7 +614,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // Resume argument type: `ResumeTy` let unstable_span = self.mark_span_with_reason(DesugaringKind::Async, span, self.allow_gen_future.clone()); - let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span, None); + let resume_ty = hir::QPath::LangItem(hir::LangItem::ResumeTy, unstable_span); let input_ty = hir::Ty { hir_id: self.next_id(), kind: hir::TyKind::Path(resume_ty), @@ -818,19 +818,16 @@ impl<'hir> LoweringContext<'_, 'hir> { span, hir::LangItem::PinNewUnchecked, arena_vec![self; ref_mut_awaitee], - Some(expr_hir_id), ); let get_context = self.expr_call_lang_item_fn_mut( gen_future_span, hir::LangItem::GetContext, arena_vec![self; task_context], - Some(expr_hir_id), ); let call = self.expr_call_lang_item_fn( span, hir::LangItem::FuturePoll, arena_vec![self; new_unchecked, get_context], - Some(expr_hir_id), ); self.arena.alloc(self.expr_unsafe(call)) }; @@ -843,12 +840,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let (x_pat, x_pat_hid) = self.pat_ident(gen_future_span, x_ident); let x_expr = self.expr_ident(gen_future_span, x_ident, x_pat_hid); let ready_field = self.single_pat_field(gen_future_span, x_pat); - let ready_pat = self.pat_lang_item_variant( - span, - hir::LangItem::PollReady, - ready_field, - Some(expr_hir_id), - ); + let ready_pat = self.pat_lang_item_variant(span, hir::LangItem::PollReady, ready_field); let break_x = self.with_loop_scope(loop_node_id, move |this| { let expr_break = hir::ExprKind::Break(this.lower_loop_destination(None), Some(x_expr)); @@ -859,12 +851,7 @@ impl<'hir> LoweringContext<'_, 'hir> { // `::std::task::Poll::Pending => {}` let pending_arm = { - let pending_pat = self.pat_lang_item_variant( - span, - hir::LangItem::PollPending, - &[], - Some(expr_hir_id), - ); + let pending_pat = self.pat_lang_item_variant(span, hir::LangItem::PollPending, &[]); let empty_block = self.expr_block_empty(span); self.arm(pending_pat, empty_block) }; @@ -922,7 +909,6 @@ impl<'hir> LoweringContext<'_, 'hir> { span, hir::LangItem::IntoFutureIntoFuture, arena_vec![self; expr], - Some(expr_hir_id), ); // match { @@ -1379,8 +1365,7 @@ impl<'hir> LoweringContext<'_, 'hir> { fn lower_expr_range_closed(&mut self, span: Span, e1: &Expr, e2: &Expr) -> hir::ExprKind<'hir> { let e1 = self.lower_expr_mut(e1); let e2 = self.lower_expr_mut(e2); - let fn_path = - hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span), None); + let fn_path = hir::QPath::LangItem(hir::LangItem::RangeInclusiveNew, self.lower_span(span)); let fn_expr = self.arena.alloc(self.expr(span, hir::ExprKind::Path(fn_path))); hir::ExprKind::Call(fn_expr, arena_vec![self; e1, e2]) } @@ -1421,7 +1406,7 @@ impl<'hir> LoweringContext<'_, 'hir> { ); hir::ExprKind::Struct( - self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span), None)), + self.arena.alloc(hir::QPath::LangItem(lang_item, self.lower_span(span))), fields, None, ) @@ -1590,7 +1575,6 @@ impl<'hir> LoweringContext<'_, 'hir> { head_span, hir::LangItem::IteratorNext, arena_vec![self; ref_mut_iter], - None, ); let arms = arena_vec![self; none_arm, some_arm]; @@ -1619,7 +1603,6 @@ impl<'hir> LoweringContext<'_, 'hir> { head_span, hir::LangItem::IntoIterIntoIter, arena_vec![self; head], - None, ) }; @@ -1675,7 +1658,6 @@ impl<'hir> LoweringContext<'_, 'hir> { unstable_span, hir::LangItem::TryTraitBranch, arena_vec![self; sub_expr], - None, ) }; @@ -1880,9 +1862,8 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, lang_item: hir::LangItem, args: &'hir [hir::Expr<'hir>], - hir_id: Option, ) -> hir::Expr<'hir> { - let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item, hir_id)); + let path = self.arena.alloc(self.expr_lang_item_path(span, lang_item)); self.expr_call_mut(span, path, args) } @@ -1891,21 +1872,12 @@ impl<'hir> LoweringContext<'_, 'hir> { span: Span, lang_item: hir::LangItem, args: &'hir [hir::Expr<'hir>], - hir_id: Option, ) -> &'hir hir::Expr<'hir> { - self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args, hir_id)) + self.arena.alloc(self.expr_call_lang_item_fn_mut(span, lang_item, args)) } - fn expr_lang_item_path( - &mut self, - span: Span, - lang_item: hir::LangItem, - hir_id: Option, - ) -> hir::Expr<'hir> { - self.expr( - span, - hir::ExprKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span), hir_id)), - ) + fn expr_lang_item_path(&mut self, span: Span, lang_item: hir::LangItem) -> hir::Expr<'hir> { + self.expr(span, hir::ExprKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span)))) } /// `::name` @@ -1918,7 +1890,7 @@ impl<'hir> LoweringContext<'_, 'hir> { let path = hir::ExprKind::Path(hir::QPath::TypeRelative( self.arena.alloc(self.ty( span, - hir::TyKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span), None)), + hir::TyKind::Path(hir::QPath::LangItem(lang_item, self.lower_span(span))), )), self.arena.alloc(hir::PathSegment::new( Ident::new(name, span), diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 96af090bccd2..d14edf7b95e0 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -2304,21 +2304,21 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { fn pat_cf_continue(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { let field = self.single_pat_field(span, pat); - self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field, None) + self.pat_lang_item_variant(span, hir::LangItem::ControlFlowContinue, field) } fn pat_cf_break(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { let field = self.single_pat_field(span, pat); - self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field, None) + self.pat_lang_item_variant(span, hir::LangItem::ControlFlowBreak, field) } fn pat_some(&mut self, span: Span, pat: &'hir hir::Pat<'hir>) -> &'hir hir::Pat<'hir> { let field = self.single_pat_field(span, pat); - self.pat_lang_item_variant(span, hir::LangItem::OptionSome, field, None) + self.pat_lang_item_variant(span, hir::LangItem::OptionSome, field) } fn pat_none(&mut self, span: Span) -> &'hir hir::Pat<'hir> { - self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[], None) + self.pat_lang_item_variant(span, hir::LangItem::OptionNone, &[]) } fn single_pat_field( @@ -2341,9 +2341,8 @@ impl<'a, 'hir> LoweringContext<'a, 'hir> { span: Span, lang_item: hir::LangItem, fields: &'hir [hir::PatField<'hir>], - hir_id: Option, ) -> &'hir hir::Pat<'hir> { - let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span), hir_id); + let qpath = hir::QPath::LangItem(lang_item, self.lower_span(span)); self.pat(span, hir::PatKind::Struct(qpath, fields, false)) } diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index a09b24d34227..6d4c46553c9a 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -445,7 +445,6 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { && let hir::ExprKind::Path(hir::QPath::LangItem( LangItem::IntoIterIntoIter, _, - _, )) = call_expr.kind { // Do not suggest `.clone()` in a `for` loop, we already suggest borrowing. @@ -1346,11 +1345,8 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // }; // corresponding to the desugaring of a for loop `for in { }`. if let hir::ExprKind::Call(path, [arg]) = ex.kind - && let hir::ExprKind::Path(hir::QPath::LangItem( - LangItem::IntoIterIntoIter, - _, - _, - )) = path.kind + && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IntoIterIntoIter, _)) = + path.kind && arg.span.contains(self.issue_span) { // Find `IntoIterator::into_iter()` @@ -1368,10 +1364,10 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .. }) = stmt.kind && let hir::ExprKind::Call(path, _args) = call.kind - && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _, _)) = + && let hir::ExprKind::Path(hir::QPath::LangItem(LangItem::IteratorNext, _)) = path.kind && let hir::PatKind::Struct(path, [field, ..], _) = bind.pat.kind - && let hir::QPath::LangItem(LangItem::OptionSome, pat_span, _) = path + && let hir::QPath::LangItem(LangItem::OptionSome, pat_span) = path && call.span.contains(self.issue_span) { // Find `` and the span for the whole `for` loop. diff --git a/compiler/rustc_hir/src/hir.rs b/compiler/rustc_hir/src/hir.rs index 1d7e8dc5eaa3..d2b83d0eb00f 100644 --- a/compiler/rustc_hir/src/hir.rs +++ b/compiler/rustc_hir/src/hir.rs @@ -2058,8 +2058,8 @@ pub enum QPath<'hir> { /// the `X` and `Y` nodes each being a `TyKind::Path(QPath::TypeRelative(..))`. TypeRelative(&'hir Ty<'hir>, &'hir PathSegment<'hir>), - /// Reference to a `#[lang = "foo"]` item. `HirId` of the inner expr. - LangItem(LangItem, Span, Option), + /// Reference to a `#[lang = "foo"]` item. + LangItem(LangItem, Span), } impl<'hir> QPath<'hir> { @@ -2068,7 +2068,7 @@ impl<'hir> QPath<'hir> { match *self { QPath::Resolved(_, path) => path.span, QPath::TypeRelative(qself, ps) => qself.span.to(ps.ident.span), - QPath::LangItem(_, span, _) => span, + QPath::LangItem(_, span) => span, } } @@ -2078,7 +2078,7 @@ impl<'hir> QPath<'hir> { match *self { QPath::Resolved(_, path) => path.span, QPath::TypeRelative(qself, _) => qself.span, - QPath::LangItem(_, span, _) => span, + QPath::LangItem(_, span) => span, } } } diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index ff92d4c4a3ee..77fc9884d616 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -2546,7 +2546,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { .map(|(ty, _, _)| ty) .unwrap_or_else(|guar| Ty::new_error(tcx, guar)) } - &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span, _)) => { + &hir::TyKind::Path(hir::QPath::LangItem(lang_item, span)) => { let def_id = tcx.require_lang_item(lang_item, Some(span)); let (args, _) = self.create_args_for_ast_path( span, diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 8df01b6555c3..e9e8c7fd4fc2 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -1623,7 +1623,7 @@ impl<'a> State<'a> { self.print_ident(item_segment.ident); self.print_generic_args(item_segment.args(), colons_before_params) } - hir::QPath::LangItem(lang_item, span, _) => { + hir::QPath::LangItem(lang_item, span) => { self.word("#[lang = \""); self.print_ident(Ident::new(lang_item.name(), span)); self.word("\"]"); diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index fdf1152a2353..e5254dc49c7e 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -289,8 +289,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { ExprKind::AddrOf(kind, mutbl, oprnd) => { self.check_expr_addr_of(kind, mutbl, oprnd, expected, expr) } - ExprKind::Path(QPath::LangItem(lang_item, _, hir_id)) => { - self.check_lang_item_path(lang_item, expr, hir_id) + ExprKind::Path(QPath::LangItem(lang_item, _)) => { + self.check_lang_item_path(lang_item, expr) } ExprKind::Path(ref qpath) => self.check_expr_path(qpath, expr, &[]), ExprKind::InlineAsm(asm) => { @@ -497,9 +497,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { &self, lang_item: hir::LangItem, expr: &'tcx hir::Expr<'tcx>, - hir_id: Option, ) -> Ty<'tcx> { - self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id, hir_id).1 + self.resolve_lang_item_path(lang_item, expr.span, expr.hir_id).1 } pub(crate) fn check_expr_path( diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs index 9bacebb1039c..c5b4acd7c86f 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/_impl.rs @@ -753,7 +753,6 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { lang_item: hir::LangItem, span: Span, hir_id: hir::HirId, - expr_hir_id: Option, ) -> (Res, Ty<'tcx>) { let def_id = self.tcx.require_lang_item(lang_item, Some(span)); let def_kind = self.tcx.def_kind(def_id); @@ -770,7 +769,13 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let code = match lang_item { hir::LangItem::IntoFutureIntoFuture => { - Some(ObligationCauseCode::AwaitableExpr(expr_hir_id)) + if let hir::Node::Expr(into_future_call) = self.tcx.hir().get_parent(hir_id) + && let hir::ExprKind::Call(_, [arg0]) = &into_future_call.kind + { + Some(ObligationCauseCode::AwaitableExpr(arg0.hir_id)) + } else { + None + } } hir::LangItem::IteratorNext | hir::LangItem::IntoIterIntoIter => { Some(ObligationCauseCode::ForLoopIterator) diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs index a02073f30254..87c93afe5402 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/checks.rs @@ -1842,8 +1842,8 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { (result.map_or(Res::Err, |(kind, def_id)| Res::Def(kind, def_id)), ty) } - QPath::LangItem(lang_item, span, id) => { - let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id, id); + QPath::LangItem(lang_item, span) => { + let (res, ty) = self.resolve_lang_item_path(lang_item, span, hir_id); (res, self.handle_raw_ty(path_span, ty)) } } diff --git a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs index 034b9795bf8d..7dd19c8e15ff 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/need_type_info.rs @@ -1087,7 +1087,7 @@ impl<'a, 'tcx> FindInferSourceVisitor<'a, 'tcx> { Box::new(segment.into_iter()) } - hir::QPath::LangItem(_, _, _) => Box::new(iter::empty()), + hir::QPath::LangItem(_, _) => Box::new(iter::empty()), } } } diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 2e367df2c4f1..1ccd6fb56d9c 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -422,7 +422,7 @@ pub enum ObligationCauseCode<'tcx> { /// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y` OpaqueType, - AwaitableExpr(Option), + AwaitableExpr(hir::HirId), ForLoopIterator, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 38ef94a4d3bc..e260fcd5e756 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -1634,8 +1634,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { fn suggest_remove_await(&self, obligation: &PredicateObligation<'tcx>, err: &mut Diagnostic) { let hir = self.tcx.hir(); - if let ObligationCauseCode::AwaitableExpr(Some(hir_id)) = - obligation.cause.code().peel_derives() + if let ObligationCauseCode::AwaitableExpr(hir_id) = obligation.cause.code().peel_derives() && let hir::Node::Expr(expr) = hir.get(*hir_id) { // FIXME: use `obligation.predicate.kind()...trait_ref.self_ty()` to see if we have `()` From 4e23448c49f8e954f1412fd0ed0e892931533e36 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 23 Nov 2023 06:17:43 +0000 Subject: [PATCH 65/93] Appease the clippy --- src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs | 2 +- src/tools/clippy/clippy_lints/src/returns.rs | 2 +- .../clippy/clippy_lints/src/unnecessary_map_on_constructor.rs | 2 +- src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs | 2 +- 4 files changed, 4 insertions(+), 4 deletions(-) diff --git a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs index eb4f003d38ae..532bbbeaf032 100644 --- a/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs +++ b/src/tools/clippy/clippy_lints/src/methods/clone_on_copy.rs @@ -61,7 +61,7 @@ pub(super) fn check( // ? is a Call, makes sure not to rec *x?, but rather (*x)? ExprKind::Call(hir_callee, _) => matches!( hir_callee.kind, - ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, _, _)) + ExprKind::Path(QPath::LangItem(rustc_hir::LangItem::TryTraitBranch, ..)) ), ExprKind::MethodCall(_, self_arg, ..) if expr.hir_id == self_arg.hir_id => true, ExprKind::Match(_, _, MatchSource::TryDesugar(_) | MatchSource::AwaitDesugar) diff --git a/src/tools/clippy/clippy_lints/src/returns.rs b/src/tools/clippy/clippy_lints/src/returns.rs index 8595205691b9..14c103e70472 100644 --- a/src/tools/clippy/clippy_lints/src/returns.rs +++ b/src/tools/clippy/clippy_lints/src/returns.rs @@ -309,7 +309,7 @@ fn check_final_expr<'tcx>( let replacement = if let Some(inner_expr) = inner { // if desugar of `do yeet`, don't lint if let ExprKind::Call(path_expr, _) = inner_expr.kind - && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, _, _)) = path_expr.kind + && let ExprKind::Path(QPath::LangItem(LangItem::TryTraitFromYeet, ..)) = path_expr.kind { return; } diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs index 06c017ea15ab..25a9db36d5c7 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_map_on_constructor.rs @@ -59,7 +59,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMapOnConstructor { } }, hir::QPath::TypeRelative(_, path) => path.ident.name, - hir::QPath::LangItem(_, _, _) => return, + hir::QPath::LangItem(..) => return, }; match constructor_symbol { sym::Some | sym::Ok if path.ident.name == rustc_span::sym::map => (), diff --git a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs index 76fa15e15880..c325e4eae21f 100644 --- a/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs +++ b/src/tools/clippy/clippy_utils/src/ty/type_certainty/mod.rs @@ -170,7 +170,7 @@ fn qpath_certainty(cx: &LateContext<'_>, qpath: &QPath<'_>, resolves_to_type: bo path_segment_certainty(cx, type_certainty(cx, ty), path_segment, resolves_to_type) }, - QPath::LangItem(lang_item, _, _) => { + QPath::LangItem(lang_item, ..) => { cx.tcx .lang_items() .get(*lang_item) From 079a2e865fbe8d3a0050afdfcd5498c075611e36 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Sat, 25 Nov 2023 17:12:15 +0000 Subject: [PATCH 66/93] is_{some,ok}_and --- .../src/check/compare_impl_item/refine.rs | 2 +- compiler/rustc_lint/src/levels.rs | 2 +- compiler/rustc_middle/src/ty/util.rs | 2 +- .../rustc_mir_build/src/check_unsafety.rs | 2 +- .../rustc_mir_dataflow/src/value_analysis.rs | 2 +- .../rustc_resolve/src/late/diagnostics.rs | 2 +- .../src/traits/coherence.rs | 20 +++++++++++++------ compiler/stable_mir/src/mir/mono.rs | 2 +- 8 files changed, 21 insertions(+), 13 deletions(-) diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs index bc5029a1d5e4..bcd317f78ef0 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item/refine.rs @@ -91,7 +91,7 @@ pub(super) fn check_refining_return_position_impl_trait_in_trait<'tcx>( // This opaque also needs to be from the impl method -- otherwise, // it's a refinement to a TAIT. - if !tcx.hir().get_if_local(impl_opaque.def_id).map_or(false, |node| { + if !tcx.hir().get_if_local(impl_opaque.def_id).is_some_and(|node| { matches!( node.expect_item().expect_opaque_ty().origin, hir::OpaqueTyOrigin::AsyncFn(def_id) | hir::OpaqueTyOrigin::FnReturn(def_id) diff --git a/compiler/rustc_lint/src/levels.rs b/compiler/rustc_lint/src/levels.rs index 3fc4f0924430..c1d4ed37627f 100644 --- a/compiler/rustc_lint/src/levels.rs +++ b/compiler/rustc_lint/src/levels.rs @@ -736,7 +736,7 @@ impl<'s, P: LintLevelsProvider> LintLevelsBuilder<'s, P> { if attr.has_name(sym::doc) && attr .meta_item_list() - .map_or(false, |l| ast::attr::list_contains_name(&l, sym::hidden)) + .is_some_and(|l| ast::attr::list_contains_name(&l, sym::hidden)) { self.insert(LintId::of(MISSING_DOCS), (Level::Allow, LintLevelSource::Default)); continue; diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index e9f65d99a2ef..2ecb4e280424 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -792,7 +792,7 @@ impl<'tcx> TyCtxt<'tcx> { // If `extern_crate` is `None`, then the crate was injected (e.g., by the allocator). // Treat that kind of crate as "indirect", since it's an implementation detail of // the language. - || self.extern_crate(key.as_def_id()).map_or(false, |e| e.is_direct()) + || self.extern_crate(key.as_def_id()).is_some_and(|e| e.is_direct()) } } diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index 103b0d8e26a2..db0efd1d12ef 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -552,7 +552,7 @@ impl UnsafeOpKind { ) { let parent_id = tcx.hir().get_parent_item(hir_id); let parent_owner = tcx.hir().owner(parent_id); - let should_suggest = parent_owner.fn_sig().map_or(false, |sig| sig.header.is_unsafe()); + let should_suggest = parent_owner.fn_sig().is_some_and(|sig| sig.header.is_unsafe()); let unsafe_not_inherited_note = if should_suggest { suggest_unsafe_block.then(|| { let body_span = tcx.hir().body(parent_owner.body_id().unwrap()).value.span; diff --git a/compiler/rustc_mir_dataflow/src/value_analysis.rs b/compiler/rustc_mir_dataflow/src/value_analysis.rs index 9dcd5f22a2d8..071024a0fa35 100644 --- a/compiler/rustc_mir_dataflow/src/value_analysis.rs +++ b/compiler/rustc_mir_dataflow/src/value_analysis.rs @@ -823,7 +823,7 @@ impl Map { ) { // Allocate a value slot if it doesn't have one, and the user requested one. assert!(self.places[place].value_index.is_none()); - if tcx.layout_of(param_env.and(ty)).map_or(false, |layout| layout.abi.is_scalar()) { + if tcx.layout_of(param_env.and(ty)).is_ok_and(|layout| layout.abi.is_scalar()) { self.places[place].value_index = Some(self.value_count.into()); self.value_count += 1; } diff --git a/compiler/rustc_resolve/src/late/diagnostics.rs b/compiler/rustc_resolve/src/late/diagnostics.rs index 326fd3b2005c..8316102b5072 100644 --- a/compiler/rustc_resolve/src/late/diagnostics.rs +++ b/compiler/rustc_resolve/src/late/diagnostics.rs @@ -1869,7 +1869,7 @@ impl<'a: 'ast, 'ast, 'tcx> LateResolutionVisitor<'a, '_, 'ast, 'tcx> { ), }; - fields.map_or(false, |fields| { + fields.is_some_and(|fields| { fields .iter() .filter(|vis| !self.r.is_accessible_from(**vis, self.parent_scope.module)) diff --git a/compiler/rustc_trait_selection/src/traits/coherence.rs b/compiler/rustc_trait_selection/src/traits/coherence.rs index f3993ec25667..d3dc4b0bd326 100644 --- a/compiler/rustc_trait_selection/src/traits/coherence.rs +++ b/compiler/rustc_trait_selection/src/traits/coherence.rs @@ -361,15 +361,23 @@ fn impl_intersection_has_impossible_obligation<'a, 'cx, 'tcx>( let infcx = selcx.infcx; obligations.iter().find(|obligation| { - if infcx.next_trait_solver() { - infcx.evaluate_obligation(obligation).map_or(false, |result| !result.may_apply()) + let evaluation_result = if infcx.next_trait_solver() { + infcx.evaluate_obligation(obligation) } else { // We use `evaluate_root_obligation` to correctly track intercrate // ambiguity clauses. We cannot use this in the new solver. - selcx.evaluate_root_obligation(obligation).map_or( - false, // Overflow has occurred, and treat the obligation as possibly holding. - |result| !result.may_apply(), - ) + selcx.evaluate_root_obligation(obligation) + }; + + match evaluation_result { + Ok(result) => !result.may_apply(), + // If overflow occurs, we need to conservatively treat the goal as possibly holding, + // since there can be instantiations of this goal that don't overflow and result in + // success. This isn't much of a problem in the old solver, since we treat overflow + // fatally (this still can be encountered: ), + // but in the new solver, this is very important for correctness, since overflow + // *must* be treated as ambiguity for completeness. + Err(_overflow) => false, } }) } diff --git a/compiler/stable_mir/src/mir/mono.rs b/compiler/stable_mir/src/mir/mono.rs index 8e884f175736..9f9af5d63090 100644 --- a/compiler/stable_mir/src/mir/mono.rs +++ b/compiler/stable_mir/src/mir/mono.rs @@ -40,7 +40,7 @@ impl Instance { pub fn is_foreign_item(&self) -> bool { let item = CrateItem::try_from(*self); - item.as_ref().map_or(false, CrateItem::is_foreign_item) + item.as_ref().is_ok_and(CrateItem::is_foreign_item) } /// Get the instance type with generic substitutions applied and lifetimes erased. From bdcf91605caf75969919ae366e5e0561dcd85ea5 Mon Sep 17 00:00:00 2001 From: Michael Howell Date: Sat, 25 Nov 2023 12:20:03 -0700 Subject: [PATCH 67/93] rustdoc: replace `elemIsInParent` with `Node.contains` According to [MDN], this function is compatible with: * Chrome 16 and Edge 12 * Firefox 9 * Safari 1.1 and iOS Safari 1 These browsers are well within our [support matrix], which requires compatibility with Chrome 118, Firefox 115, Safari 17, and Edge 119. [MDN]: https://developer.mozilla.org/en-US/docs/Web/API/Node/contains#browser_compatibility [support matrix]: https://browsersl.ist/#q=last+2+Chrome+versions%2C+last+1+Firefox+version%2C+Firefox+ESR%2C+last+1+Safari+version%2C+last+1+iOS+version%2C+last+1+Edge+version%2C+last+1+UCAndroid+version --- src/librustdoc/html/static/js/main.js | 28 ++++++++--------------- src/librustdoc/html/static/js/settings.js | 4 ++-- 2 files changed, 11 insertions(+), 21 deletions(-) diff --git a/src/librustdoc/html/static/js/main.js b/src/librustdoc/html/static/js/main.js index 615fb08c76f3..7cc0f2e8f1e9 100644 --- a/src/librustdoc/html/static/js/main.js +++ b/src/librustdoc/html/static/js/main.js @@ -25,19 +25,9 @@ function showMain() { removeClass(document.getElementById(MAIN_ID), "hidden"); } -function elemIsInParent(elem, parent) { - while (elem && elem !== document.body) { - if (elem === parent) { - return true; - } - elem = elem.parentElement; - } - return false; -} - function blurHandler(event, parentElem, hideCallback) { - if (!elemIsInParent(document.activeElement, parentElem) && - !elemIsInParent(event.relatedTarget, parentElem) + if (!parentElem.contains(document.activeElement) && + !parentElem.contains(event.relatedTarget) ) { hideCallback(); } @@ -1118,7 +1108,7 @@ function preLoadCss(cssUrl) { if (ev.pointerType !== "mouse") { return; } - if (!e.TOOLTIP_FORCE_VISIBLE && !elemIsInParent(ev.relatedTarget, e)) { + if (!e.TOOLTIP_FORCE_VISIBLE && !e.contains(ev.relatedTarget)) { // See "Tooltip pointer leave gesture" below. setTooltipHoverTimeout(e, false); addClass(wrapper, "fade-out"); @@ -1178,10 +1168,10 @@ function preLoadCss(cssUrl) { function tooltipBlurHandler(event) { if (window.CURRENT_TOOLTIP_ELEMENT && - !elemIsInParent(document.activeElement, window.CURRENT_TOOLTIP_ELEMENT) && - !elemIsInParent(event.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT) && - !elemIsInParent(document.activeElement, window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE) && - !elemIsInParent(event.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE) + !window.CURRENT_TOOLTIP_ELEMENT.contains(document.activeElement) && + !window.CURRENT_TOOLTIP_ELEMENT.contains(event.relatedTarget) && + !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(document.activeElement) && + !window.CURRENT_TOOLTIP_ELEMENT.TOOLTIP_BASE.contains(event.relatedTarget) ) { // Work around a difference in the focus behaviour between Firefox, Chrome, and Safari. // When I click the button on an already-opened tooltip popover, Safari @@ -1248,8 +1238,8 @@ function preLoadCss(cssUrl) { if (ev.pointerType !== "mouse") { return; } - if (!e.TOOLTIP_FORCE_VISIBLE && - !elemIsInParent(ev.relatedTarget, window.CURRENT_TOOLTIP_ELEMENT)) { + if (!e.TOOLTIP_FORCE_VISIBLE && window.CURRENT_TOOLTIP_ELEMENT && + !window.CURRENT_TOOLTIP_ELEMENT.contains(ev.relatedTarget)) { // Tooltip pointer leave gesture: // // Designing a good hover microinteraction is a matter of guessing user diff --git a/src/librustdoc/html/static/js/settings.js b/src/librustdoc/html/static/js/settings.js index 63947789c541..70a2825265ec 100644 --- a/src/librustdoc/html/static/js/settings.js +++ b/src/librustdoc/html/static/js/settings.js @@ -1,6 +1,6 @@ // Local js definitions: /* global getSettingValue, updateLocalStorage, updateTheme */ -/* global addClass, removeClass, onEach, onEachLazy, blurHandler, elemIsInParent */ +/* global addClass, removeClass, onEach, onEachLazy, blurHandler */ /* global MAIN_ID, getVar, getSettingsButton */ "use strict"; @@ -232,7 +232,7 @@ const settingsButton = getSettingsButton(); const settingsMenu = document.getElementById("settings"); settingsButton.onclick = event => { - if (elemIsInParent(event.target, settingsMenu)) { + if (settingsMenu.contains(event.target)) { return; } event.preventDefault(); From df9f83987a0ba2aed69379fc191a4944454d7c42 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 22 Nov 2023 09:27:25 +1100 Subject: [PATCH 68/93] Remove `rustc_error_messages/messages.ftl`. It's empty, and it doesn't even make sense, because `rustc_error_messages` is a lower-level crate than `rustc_errors`. --- Cargo.lock | 1 - compiler/rustc_driver_impl/src/lib.rs | 1 - compiler/rustc_error_messages/Cargo.toml | 1 - compiler/rustc_error_messages/messages.ftl | 1 - compiler/rustc_error_messages/src/lib.rs | 3 --- 5 files changed, 7 deletions(-) delete mode 100644 compiler/rustc_error_messages/messages.ftl diff --git a/Cargo.lock b/Cargo.lock index d6dc5c7a96eb..744c91a4aa24 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3771,7 +3771,6 @@ dependencies = [ "intl-memoizer", "rustc_baked_icu_data", "rustc_data_structures", - "rustc_fluent_macro", "rustc_macros", "rustc_serialize", "rustc_span", diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 5ab14fbc6874..db77fe847d08 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -114,7 +114,6 @@ pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ rustc_builtin_macros::DEFAULT_LOCALE_RESOURCE, rustc_codegen_ssa::DEFAULT_LOCALE_RESOURCE, rustc_const_eval::DEFAULT_LOCALE_RESOURCE, - rustc_error_messages::DEFAULT_LOCALE_RESOURCE, rustc_errors::DEFAULT_LOCALE_RESOURCE, rustc_expand::DEFAULT_LOCALE_RESOURCE, rustc_hir_analysis::DEFAULT_LOCALE_RESOURCE, diff --git a/compiler/rustc_error_messages/Cargo.toml b/compiler/rustc_error_messages/Cargo.toml index 1969feed48ff..5b6b8b3f183f 100644 --- a/compiler/rustc_error_messages/Cargo.toml +++ b/compiler/rustc_error_messages/Cargo.toml @@ -13,7 +13,6 @@ icu_provider_adapters = "1.2" intl-memoizer = "0.5.1" rustc_baked_icu_data = { path = "../rustc_baked_icu_data" } rustc_data_structures = { path = "../rustc_data_structures" } -rustc_fluent_macro = { path = "../rustc_fluent_macro" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } rustc_span = { path = "../rustc_span" } diff --git a/compiler/rustc_error_messages/messages.ftl b/compiler/rustc_error_messages/messages.ftl deleted file mode 100644 index e62923744482..000000000000 --- a/compiler/rustc_error_messages/messages.ftl +++ /dev/null @@ -1 +0,0 @@ -# satisfy tidy lint by having a line in this file diff --git a/compiler/rustc_error_messages/src/lib.rs b/compiler/rustc_error_messages/src/lib.rs index 35bd45e64a26..fc544c31e893 100644 --- a/compiler/rustc_error_messages/src/lib.rs +++ b/compiler/rustc_error_messages/src/lib.rs @@ -15,7 +15,6 @@ use fluent_bundle::FluentResource; use fluent_syntax::parser::ParserError; use icu_provider_adapters::fallback::{LocaleFallbackProvider, LocaleFallbacker}; use rustc_data_structures::sync::{IntoDynSyncSend, Lrc}; -use rustc_fluent_macro::fluent_messages; use rustc_macros::{Decodable, Encodable}; use rustc_span::Span; use std::borrow::Cow; @@ -38,8 +37,6 @@ use intl_memoizer::IntlLangMemoizer; pub use fluent_bundle::{self, types::FluentType, FluentArgs, FluentError, FluentValue}; pub use unic_langid::{langid, LanguageIdentifier}; -fluent_messages! { "../messages.ftl" } - pub type FluentBundle = IntoDynSyncSend>; From a733082be9962317e41f357a9708632a759c28b2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 22 Nov 2023 09:22:39 +1100 Subject: [PATCH 69/93] Avoid need for `{D,Subd}iagnosticMessage` imports. The `fluent_messages!` macro produces uses of `crate::{D,Subd}iagnosticMessage`, which means that every crate using the macro must have this import: ``` use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; ``` This commit changes the macro to instead use `rustc_errors::{D,Subd}iagnosticMessage`, which avoids the need for the imports. --- compiler/rustc_ast_lowering/src/lib.rs | 4 +-- compiler/rustc_ast_passes/src/lib.rs | 1 - compiler/rustc_attr/src/lib.rs | 1 - compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_builtin_macros/src/lib.rs | 1 - compiler/rustc_codegen_gcc/src/lib.rs | 2 +- compiler/rustc_codegen_llvm/src/lib.rs | 2 +- compiler/rustc_codegen_ssa/src/lib.rs | 1 - compiler/rustc_const_eval/src/lib.rs | 1 - compiler/rustc_driver_impl/src/lib.rs | 2 +- compiler/rustc_expand/src/lib.rs | 1 - compiler/rustc_fluent_macro/src/fluent.rs | 33 ++++++++++------------- compiler/rustc_hir_analysis/src/lib.rs | 1 - compiler/rustc_hir_typeck/src/lib.rs | 5 +--- compiler/rustc_incremental/src/lib.rs | 1 - compiler/rustc_infer/src/lib.rs | 1 - compiler/rustc_interface/src/lib.rs | 1 - compiler/rustc_lint/src/lib.rs | 1 - compiler/rustc_metadata/src/lib.rs | 1 - compiler/rustc_middle/src/lib.rs | 1 - compiler/rustc_mir_build/src/lib.rs | 1 - compiler/rustc_mir_dataflow/src/lib.rs | 1 - compiler/rustc_mir_transform/src/lib.rs | 1 - compiler/rustc_monomorphize/src/lib.rs | 1 - compiler/rustc_parse/src/lib.rs | 1 - compiler/rustc_passes/src/lib.rs | 1 - compiler/rustc_privacy/src/lib.rs | 1 - compiler/rustc_query_system/src/lib.rs | 1 - compiler/rustc_resolve/src/lib.rs | 4 +-- compiler/rustc_session/src/lib.rs | 1 - compiler/rustc_trait_selection/src/lib.rs | 1 - compiler/rustc_ty_utils/src/lib.rs | 1 - tests/ui-fulldeps/fluent-messages/test.rs | 2 +- 33 files changed, 22 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index 96af090bccd2..ea21c9660907 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -55,9 +55,7 @@ use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{ - DiagnosticArgFromDisplay, DiagnosticMessage, Handler, StashKey, SubdiagnosticMessage, -}; +use rustc_errors::{DiagnosticArgFromDisplay, Handler, StashKey}; use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 6187258a9500..55cdc939d27a 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -15,7 +15,6 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; pub mod ast_validation; diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index 5da5a3cb342c..d60b8c19e170 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -14,7 +14,6 @@ #[macro_use] extern crate rustc_macros; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; mod builtin; diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 804060d00ed0..ae7ea5fd0981 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -22,7 +22,7 @@ extern crate tracing; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; -use rustc_errors::{Diagnostic, DiagnosticBuilder, DiagnosticMessage, SubdiagnosticMessage}; +use rustc_errors::{Diagnostic, DiagnosticBuilder}; use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index ae097dec8f1e..c61f26ca07bc 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -23,7 +23,6 @@ extern crate tracing; use crate::deriving::*; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; use rustc_fluent_macro::fluent_messages; diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index 8c7bae0c8866..dcf7a4124c27 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -101,7 +101,7 @@ use rustc_codegen_ssa::target_features::supported_target_features; use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods}; -use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, SubdiagnosticMessage}; +use rustc_errors::{ErrorGuaranteed, Handler}; use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index 8d809648aca7..fac5c551c73b 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -40,7 +40,7 @@ use rustc_codegen_ssa::traits::*; use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; use rustc_data_structures::fx::FxIndexMap; -use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, FatalError, Handler, SubdiagnosticMessage}; +use rustc_errors::{ErrorGuaranteed, FatalError, Handler}; use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 8a82a37df9cc..0d0babe365dd 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -27,7 +27,6 @@ extern crate rustc_middle; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir::def_id::CrateNum; use rustc_middle::dep_graph::WorkProduct; diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 26ff757ca590..2997e5f76761 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -39,7 +39,6 @@ pub mod util; pub use errors::ReportErrorExt; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_middle::{ty, util::Providers}; diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index db77fe847d08..bf78dbd6583d 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -28,7 +28,7 @@ use rustc_data_structures::profiling::{ use rustc_data_structures::sync::SeqCst; use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{markdown, ColorConfig}; -use rustc_errors::{DiagnosticMessage, ErrorGuaranteed, Handler, PResult, SubdiagnosticMessage}; +use rustc_errors::{ErrorGuaranteed, Handler, PResult}; use rustc_feature::find_gated_cfg; use rustc_fluent_macro::fluent_messages; use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index cb084a85e47d..f90f992e80e9 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -23,7 +23,6 @@ extern crate tracing; extern crate proc_macro as pm; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; mod placeholders; diff --git a/compiler/rustc_fluent_macro/src/fluent.rs b/compiler/rustc_fluent_macro/src/fluent.rs index 7479e4ef2b31..3b1b63455edd 100644 --- a/compiler/rustc_fluent_macro/src/fluent.rs +++ b/compiler/rustc_fluent_macro/src/fluent.rs @@ -57,20 +57,20 @@ fn finish(body: TokenStream, resource: TokenStream) -> proc_macro::TokenStream { /// identifiers for different subdiagnostic kinds. pub mod _subdiag { /// Default for `#[help]` - pub const help: crate::SubdiagnosticMessage = - crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("help")); + pub const help: rustc_errors::SubdiagnosticMessage = + rustc_errors::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("help")); /// Default for `#[note]` - pub const note: crate::SubdiagnosticMessage = - crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note")); + pub const note: rustc_errors::SubdiagnosticMessage = + rustc_errors::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("note")); /// Default for `#[warn]` - pub const warn: crate::SubdiagnosticMessage = - crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("warn")); + pub const warn: rustc_errors::SubdiagnosticMessage = + rustc_errors::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("warn")); /// Default for `#[label]` - pub const label: crate::SubdiagnosticMessage = - crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("label")); + pub const label: rustc_errors::SubdiagnosticMessage = + rustc_errors::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("label")); /// Default for `#[suggestion]` - pub const suggestion: crate::SubdiagnosticMessage = - crate::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("suggestion")); + pub const suggestion: rustc_errors::SubdiagnosticMessage = + rustc_errors::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed("suggestion")); } } } @@ -248,11 +248,8 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok format!("Constant referring to Fluent message `{name}` from `{crate_name}`"); constants.extend(quote! { #[doc = #docstr] - pub const #snake_name: crate::DiagnosticMessage = - crate::DiagnosticMessage::FluentIdentifier( - std::borrow::Cow::Borrowed(#name), - None - ); + pub const #snake_name: rustc_errors::DiagnosticMessage = + rustc_errors::DiagnosticMessage::FluentIdentifier(std::borrow::Cow::Borrowed(#name), None); }); for Attribute { id: Identifier { name: attr_name }, .. } in attributes { @@ -279,10 +276,8 @@ pub(crate) fn fluent_messages(input: proc_macro::TokenStream) -> proc_macro::Tok ); constants.extend(quote! { #[doc = #msg] - pub const #snake_name: crate::SubdiagnosticMessage = - crate::SubdiagnosticMessage::FluentAttr( - std::borrow::Cow::Borrowed(#attr_name) - ); + pub const #snake_name: rustc_errors::SubdiagnosticMessage = + rustc_errors::SubdiagnosticMessage::FluentAttr(std::borrow::Cow::Borrowed(#attr_name)); }); } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index bcc2051888b2..71fd09e8bdbf 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -99,7 +99,6 @@ pub mod structured_errors; mod variance; use rustc_errors::ErrorGuaranteed; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_middle::middle; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index 66a0f4ed9def..d85247955d02 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -52,10 +52,7 @@ use crate::expectation::Expectation; use crate::fn_ctxt::RawTy; use crate::gather_locals::GatherLocalsVisitor; use rustc_data_structures::unord::UnordSet; -use rustc_errors::{ - struct_span_err, DiagnosticId, DiagnosticMessage, ErrorGuaranteed, MultiSpan, - SubdiagnosticMessage, -}; +use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed, MultiSpan}; use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 81d4d914287e..e9a5dded0e57 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -28,7 +28,6 @@ pub use persist::save_work_product_index; pub use persist::setup_dep_graph; pub use persist::LoadResult; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index 4ca3ced21ee2..bcb93e7759dd 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -37,7 +37,6 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; mod errors; diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index ffa2667a351e..fc01c39ed9e4 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -13,7 +13,6 @@ #[macro_use] extern crate tracing; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; mod callbacks; diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index a48a8bd71b9a..90ecb2f79273 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -90,7 +90,6 @@ mod unused; pub use array_into_iter::ARRAY_INTO_ITER; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir::def_id::LocalModDefId; use rustc_middle::query::Providers; diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index d326a3aa8d02..199aa9b5337a 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -31,7 +31,6 @@ extern crate rustc_middle; extern crate tracing; pub use rmeta::provide; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; mod dependency_format; diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index e5244c1862e4..356092a49593 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -77,7 +77,6 @@ extern crate tracing; #[macro_use] extern crate smallvec; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; #[cfg(test)] diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 745c3046d22c..1f795b30fb79 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -24,7 +24,6 @@ mod thir; use rustc_middle::query::Providers; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index cd3378375d81..562ee42b25eb 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -13,7 +13,6 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_middle::ty; diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index a3a10b138c76..5b8617875400 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -118,7 +118,6 @@ use rustc_const_eval::transform::promote_consts; use rustc_const_eval::transform::validate; use rustc_mir_dataflow::rustc_peek; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 5f05020acae9..98c69fc700c8 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -10,7 +10,6 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir::lang_items::LangItem; use rustc_middle::query::{Providers, TyCtxtAt}; diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index c012a8663329..7b9520bea50f 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -20,7 +20,6 @@ use rustc_ast::{AttrItem, Attribute, MetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 9eb1df0b2e28..68c31423b58b 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -23,7 +23,6 @@ extern crate rustc_middle; #[macro_use] extern crate tracing; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_middle::query::Providers; diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 4324afe42b38..d6d3f8286423 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -19,7 +19,6 @@ use rustc_ast::MacroDef; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 2ed420f35643..8e5e94291bd9 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -14,7 +14,6 @@ extern crate rustc_data_structures; #[macro_use] extern crate rustc_macros; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; pub mod cache; diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index 23e8ebc49b0b..c131f70f087f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -37,9 +37,7 @@ use rustc_data_structures::fx::{FxHashMap, FxHashSet, FxIndexMap, FxIndexSet}; use rustc_data_structures::intern::Interned; use rustc_data_structures::steal::Steal; use rustc_data_structures::sync::{FreezeReadGuard, Lrc}; -use rustc_errors::{ - Applicability, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, SubdiagnosticMessage, -}; +use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; use rustc_fluent_macro::fluent_messages; diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index 17ac3e991c58..ea015fd3c683 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -20,7 +20,6 @@ pub mod errors; #[macro_use] extern crate tracing; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; pub mod utils; diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index de52fa6c4476..536fdcb59dd1 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -37,7 +37,6 @@ extern crate rustc_middle; #[macro_use] extern crate smallvec; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; pub mod errors; diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 8321732b7663..7a99f95386c9 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -24,7 +24,6 @@ extern crate rustc_middle; #[macro_use] extern crate tracing; -use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; use rustc_middle::query::Providers; diff --git a/tests/ui-fulldeps/fluent-messages/test.rs b/tests/ui-fulldeps/fluent-messages/test.rs index 1dd6d211b3f0..d19c6956cbdf 100644 --- a/tests/ui-fulldeps/fluent-messages/test.rs +++ b/tests/ui-fulldeps/fluent-messages/test.rs @@ -2,7 +2,7 @@ #![feature(rustc_private)] #![crate_type = "lib"] - +extern crate rustc_errors; extern crate rustc_fluent_macro; use rustc_fluent_macro::fluent_messages; From 1a4219da43461fa37a9a68f9e57bf019ac9091e0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 22 Nov 2023 12:48:18 +1100 Subject: [PATCH 70/93] Add a useful comment. --- compiler/rustc_fluent_macro/src/lib.rs | 4 ++++ 1 file changed, 4 insertions(+) diff --git a/compiler/rustc_fluent_macro/src/lib.rs b/compiler/rustc_fluent_macro/src/lib.rs index b041fad1f13e..fc65d1eb8c4c 100644 --- a/compiler/rustc_fluent_macro/src/lib.rs +++ b/compiler/rustc_fluent_macro/src/lib.rs @@ -61,6 +61,10 @@ mod fluent; /// ); /// err.emit(); /// ``` +/// +/// Note: any crate using this macro must also have a dependency on +/// `rustc_errors`, because the generated code refers to things from that +/// crate. #[proc_macro] pub fn fluent_messages(input: TokenStream) -> TokenStream { fluent::fluent_messages(input) From 57cd5e6551ffcd071aa0496f9b8c0ed28dca7ffe Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 22 Nov 2023 09:53:07 +1100 Subject: [PATCH 71/93] Use `rustc_fluent_macro::fluent_messages!` directly. Currently we always do this: ``` use rustc_fluent_macro::fluent_messages; ... fluent_messages! { "./example.ftl" } ``` But there is no need, we can just do this everywhere: ``` rustc_fluent_macro::fluent_messages! { "./example.ftl" } ``` which is shorter. --- compiler/rustc_ast_lowering/src/lib.rs | 3 +- compiler/rustc_ast_passes/src/lib.rs | 4 +- compiler/rustc_attr/src/lib.rs | 4 +- compiler/rustc_borrowck/src/lib.rs | 3 +- compiler/rustc_builtin_macros/src/lib.rs | 3 +- compiler/rustc_codegen_gcc/src/lib.rs | 3 +- compiler/rustc_codegen_llvm/src/lib.rs | 3 +- compiler/rustc_codegen_ssa/src/lib.rs | 3 +- compiler/rustc_const_eval/src/lib.rs | 3 +- compiler/rustc_driver_impl/src/lib.rs | 3 +- compiler/rustc_errors/src/lib.rs | 3 +- compiler/rustc_expand/src/lib.rs | 4 +- compiler/rustc_hir_analysis/src/lib.rs | 3 +- compiler/rustc_hir_typeck/src/lib.rs | 3 +- compiler/rustc_incremental/src/lib.rs | 4 +- compiler/rustc_infer/src/lib.rs | 4 +- compiler/rustc_interface/src/lib.rs | 4 +- compiler/rustc_lint/src/lib.rs | 3 +- compiler/rustc_metadata/src/lib.rs | 3 +- compiler/rustc_middle/src/lib.rs | 4 +- compiler/rustc_mir_build/src/lib.rs | 4 +- compiler/rustc_mir_dataflow/src/lib.rs | 3 +- compiler/rustc_mir_transform/src/lib.rs | 4 +- compiler/rustc_monomorphize/src/lib.rs | 3 +- compiler/rustc_parse/src/lib.rs | 3 +- compiler/rustc_passes/src/lib.rs | 3 +- compiler/rustc_privacy/src/lib.rs | 3 +- compiler/rustc_query_system/src/lib.rs | 4 +- compiler/rustc_resolve/src/lib.rs | 3 +- compiler/rustc_session/src/lib.rs | 4 +- compiler/rustc_trait_selection/src/lib.rs | 4 +- compiler/rustc_ty_utils/src/lib.rs | 3 +- tests/ui-fulldeps/fluent-messages/test.rs | 41 +--- tests/ui-fulldeps/fluent-messages/test.stderr | 78 +++---- .../ui-fulldeps/internal-lints/diagnostics.rs | 3 +- .../internal-lints/diagnostics.stderr | 10 +- .../diagnostic-derive-doc-comment-field.rs | 3 +- ...diagnostic-derive-doc-comment-field.stderr | 4 +- .../session-diagnostic/diagnostic-derive.rs | 3 +- .../diagnostic-derive.stderr | 190 +++++++++--------- .../session-diagnostic/invalid-variable.rs | 3 +- .../subdiagnostic-derive.rs | 3 +- .../subdiagnostic-derive.stderr | 182 ++++++++--------- 43 files changed, 279 insertions(+), 349 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/lib.rs b/compiler/rustc_ast_lowering/src/lib.rs index ea21c9660907..bf4eb006e6a1 100644 --- a/compiler/rustc_ast_lowering/src/lib.rs +++ b/compiler/rustc_ast_lowering/src/lib.rs @@ -56,7 +56,6 @@ use rustc_data_structures::sorted_map::SortedMap; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_data_structures::sync::Lrc; use rustc_errors::{DiagnosticArgFromDisplay, Handler, StashKey}; -use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, LifetimeRes, Namespace, PartialRes, PerNS, Res}; use rustc_hir::def_id::{LocalDefId, CRATE_DEF_ID, LOCAL_CRATE}; @@ -92,7 +91,7 @@ mod lifetime_collector; mod pat; mod path; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } struct LoweringContext<'a, 'hir> { tcx: TyCtxt<'hir>, diff --git a/compiler/rustc_ast_passes/src/lib.rs b/compiler/rustc_ast_passes/src/lib.rs index 55cdc939d27a..ba09183374e1 100644 --- a/compiler/rustc_ast_passes/src/lib.rs +++ b/compiler/rustc_ast_passes/src/lib.rs @@ -15,12 +15,10 @@ #![deny(rustc::untranslatable_diagnostic)] #![deny(rustc::diagnostic_outside_of_impl)] -use rustc_fluent_macro::fluent_messages; - pub mod ast_validation; mod errors; pub mod feature_gate; pub mod node_count; pub mod show_span; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_attr/src/lib.rs b/compiler/rustc_attr/src/lib.rs index d60b8c19e170..3c5bcecddeaa 100644 --- a/compiler/rustc_attr/src/lib.rs +++ b/compiler/rustc_attr/src/lib.rs @@ -14,8 +14,6 @@ #[macro_use] extern crate rustc_macros; -use rustc_fluent_macro::fluent_messages; - mod builtin; mod session_diagnostics; @@ -28,4 +26,4 @@ pub use rustc_ast::attr::*; pub(crate) use rustc_session::HashStableContext; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index ae7ea5fd0981..822519f2f081 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -23,7 +23,6 @@ extern crate tracing; use rustc_data_structures::fx::{FxIndexMap, FxIndexSet}; use rustc_data_structures::graph::dominators::Dominators; use rustc_errors::{Diagnostic, DiagnosticBuilder}; -use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def_id::LocalDefId; use rustc_index::bit_set::{BitSet, ChunkedBitSet}; @@ -98,7 +97,7 @@ use places_conflict::{places_conflict, PlaceConflictBias}; use region_infer::RegionInferenceContext; use renumber::RegionCtxt; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } // FIXME(eddyb) perhaps move this somewhere more centrally. #[derive(Debug)] diff --git a/compiler/rustc_builtin_macros/src/lib.rs b/compiler/rustc_builtin_macros/src/lib.rs index c61f26ca07bc..f60b73fbe9b1 100644 --- a/compiler/rustc_builtin_macros/src/lib.rs +++ b/compiler/rustc_builtin_macros/src/lib.rs @@ -25,7 +25,6 @@ use crate::deriving::*; use rustc_expand::base::{MacroExpanderFn, ResolverExpand, SyntaxExtensionKind}; use rustc_expand::proc_macro::BangProcMacro; -use rustc_fluent_macro::fluent_messages; use rustc_span::symbol::sym; mod alloc_error_handler; @@ -58,7 +57,7 @@ pub mod proc_macro_harness; pub mod standard_library_imports; pub mod test_harness; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn register_builtin_macros(resolver: &mut dyn ResolverExpand) { let mut register = |name, kind| resolver.register_builtin_macro(name, kind); diff --git a/compiler/rustc_codegen_gcc/src/lib.rs b/compiler/rustc_codegen_gcc/src/lib.rs index dcf7a4124c27..d54057615d2d 100644 --- a/compiler/rustc_codegen_gcc/src/lib.rs +++ b/compiler/rustc_codegen_gcc/src/lib.rs @@ -102,7 +102,6 @@ use rustc_data_structures::fx::FxIndexMap; use rustc_data_structures::sync::IntoDynSyncSend; use rustc_codegen_ssa::traits::{CodegenBackend, ExtraBackendMethods, ThinBufferMethods, WriteBackendMethods}; use rustc_errors::{ErrorGuaranteed, Handler}; -use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::util::Providers; @@ -116,7 +115,7 @@ use tempfile::TempDir; use crate::back::lto::ModuleBuffer; use crate::gcc_util::target_cpu; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub struct PrintOnPanic String>(pub F); diff --git a/compiler/rustc_codegen_llvm/src/lib.rs b/compiler/rustc_codegen_llvm/src/lib.rs index fac5c551c73b..f8a0423e9b10 100644 --- a/compiler/rustc_codegen_llvm/src/lib.rs +++ b/compiler/rustc_codegen_llvm/src/lib.rs @@ -41,7 +41,6 @@ use rustc_codegen_ssa::ModuleCodegen; use rustc_codegen_ssa::{CodegenResults, CompiledModule}; use rustc_data_structures::fx::FxIndexMap; use rustc_errors::{ErrorGuaranteed, FatalError, Handler}; -use rustc_fluent_macro::fluent_messages; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::ty::TyCtxt; @@ -92,7 +91,7 @@ mod type_of; mod va_arg; mod value; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[derive(Clone)] pub struct LlvmCodegenBackend(()); diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index 0d0babe365dd..c65a0e968a5a 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -27,7 +27,6 @@ extern crate rustc_middle; use rustc_ast as ast; use rustc_data_structures::fx::{FxHashMap, FxHashSet}; use rustc_data_structures::sync::Lrc; -use rustc_fluent_macro::fluent_messages; use rustc_hir::def_id::CrateNum; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::debugger_visualizer::DebuggerVisualizerFile; @@ -59,7 +58,7 @@ pub mod mono_item; pub mod target_features; pub mod traits; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub struct ModuleCodegen { /// The name of the module. When the crate may be saved between diff --git a/compiler/rustc_const_eval/src/lib.rs b/compiler/rustc_const_eval/src/lib.rs index 2997e5f76761..d6c36ccc5ec8 100644 --- a/compiler/rustc_const_eval/src/lib.rs +++ b/compiler/rustc_const_eval/src/lib.rs @@ -39,10 +39,9 @@ pub mod util; pub use errors::ReportErrorExt; -use rustc_fluent_macro::fluent_messages; use rustc_middle::{ty, util::Providers}; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { const_eval::provide(providers); diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index bf78dbd6583d..e7cc3ae4d551 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -30,7 +30,6 @@ use rustc_errors::registry::{InvalidErrorCode, Registry}; use rustc_errors::{markdown, ColorConfig}; use rustc_errors::{ErrorGuaranteed, Handler, PResult}; use rustc_feature::find_gated_cfg; -use rustc_fluent_macro::fluent_messages; use rustc_interface::util::{self, collect_crate_types, get_codegen_backend}; use rustc_interface::{interface, Queries}; use rustc_lint::unerased_lint_store; @@ -102,7 +101,7 @@ use crate::session_diagnostics::{ RLinkWrongFileType, RlinkNotAFile, RlinkUnableToRead, }; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub static DEFAULT_LOCALE_RESOURCES: &[&str] = &[ // tidy-alphabetical-start diff --git a/compiler/rustc_errors/src/lib.rs b/compiler/rustc_errors/src/lib.rs index a3cda5aeab54..6bd87f54140e 100644 --- a/compiler/rustc_errors/src/lib.rs +++ b/compiler/rustc_errors/src/lib.rs @@ -41,7 +41,6 @@ pub use rustc_error_messages::{ fallback_fluent_bundle, fluent_bundle, DelayDm, DiagnosticMessage, FluentBundle, LanguageIdentifier, LazyFallbackBundle, MultiSpan, SpanLabel, SubdiagnosticMessage, }; -use rustc_fluent_macro::fluent_messages; pub use rustc_lint_defs::{pluralize, Applicability}; use rustc_span::source_map::SourceMap; pub use rustc_span::ErrorGuaranteed; @@ -82,7 +81,7 @@ pub use snippet::Style; pub type PErr<'a> = DiagnosticBuilder<'a, ErrorGuaranteed>; pub type PResult<'a, T> = Result>; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } // `PResult` is used a lot. Make sure it doesn't unintentionally get bigger. // (See also the comment on `DiagnosticBuilderInner`'s `diagnostic` field.) diff --git a/compiler/rustc_expand/src/lib.rs b/compiler/rustc_expand/src/lib.rs index f90f992e80e9..bed667048c85 100644 --- a/compiler/rustc_expand/src/lib.rs +++ b/compiler/rustc_expand/src/lib.rs @@ -23,8 +23,6 @@ extern crate tracing; extern crate proc_macro as pm; -use rustc_fluent_macro::fluent_messages; - mod placeholders; mod proc_macro_server; @@ -66,4 +64,4 @@ mod mut_visit { mod tests; } -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_hir_analysis/src/lib.rs b/compiler/rustc_hir_analysis/src/lib.rs index 71fd09e8bdbf..1c3ac2974571 100644 --- a/compiler/rustc_hir_analysis/src/lib.rs +++ b/compiler/rustc_hir_analysis/src/lib.rs @@ -99,7 +99,6 @@ pub mod structured_errors; mod variance; use rustc_errors::ErrorGuaranteed; -use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_middle::middle; use rustc_middle::query::Providers; @@ -114,7 +113,7 @@ use astconv::{AstConv, OnlySelfBounds}; use bounds::Bounds; use rustc_hir::def::DefKind; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } fn require_c_abi_if_c_variadic(tcx: TyCtxt<'_>, decl: &hir::FnDecl<'_>, abi: Abi, span: Span) { const CONVENTIONS_UNSTABLE: &str = "`C`, `cdecl`, `aapcs`, `win64`, `sysv64` or `efiapi`"; diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index d85247955d02..f43e1c575a04 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -53,7 +53,6 @@ use crate::fn_ctxt::RawTy; use crate::gather_locals::GatherLocalsVisitor; use rustc_data_structures::unord::UnordSet; use rustc_errors::{struct_span_err, DiagnosticId, ErrorGuaranteed, MultiSpan}; -use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::intravisit::Visitor; @@ -68,7 +67,7 @@ use rustc_session::config; use rustc_span::def_id::{DefId, LocalDefId}; use rustc_span::Span; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[macro_export] macro_rules! type_error_struct { diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index e9a5dded0e57..367a15e14430 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -28,6 +28,4 @@ pub use persist::save_work_product_index; pub use persist::setup_dep_graph; pub use persist::LoadResult; -use rustc_fluent_macro::fluent_messages; - -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_infer/src/lib.rs b/compiler/rustc_infer/src/lib.rs index bcb93e7759dd..221b78048cbc 100644 --- a/compiler/rustc_infer/src/lib.rs +++ b/compiler/rustc_infer/src/lib.rs @@ -37,10 +37,8 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; -use rustc_fluent_macro::fluent_messages; - mod errors; pub mod infer; pub mod traits; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_interface/src/lib.rs b/compiler/rustc_interface/src/lib.rs index fc01c39ed9e4..21d5b0f41693 100644 --- a/compiler/rustc_interface/src/lib.rs +++ b/compiler/rustc_interface/src/lib.rs @@ -13,8 +13,6 @@ #[macro_use] extern crate tracing; -use rustc_fluent_macro::fluent_messages; - mod callbacks; mod errors; pub mod interface; @@ -31,4 +29,4 @@ pub use queries::Queries; #[cfg(test)] mod tests; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_lint/src/lib.rs b/compiler/rustc_lint/src/lib.rs index 90ecb2f79273..39ecc2dfcc0a 100644 --- a/compiler/rustc_lint/src/lib.rs +++ b/compiler/rustc_lint/src/lib.rs @@ -90,7 +90,6 @@ mod unused; pub use array_into_iter::ARRAY_INTO_ITER; -use rustc_fluent_macro::fluent_messages; use rustc_hir::def_id::LocalModDefId; use rustc_middle::query::Providers; use rustc_middle::ty::TyCtxt; @@ -137,7 +136,7 @@ pub use rustc_session::lint::Level::{self, *}; pub use rustc_session::lint::{BufferedEarlyLint, FutureIncompatibleInfo, Lint, LintId}; pub use rustc_session::lint::{LintPass, LintVec}; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { levels::provide(providers); diff --git a/compiler/rustc_metadata/src/lib.rs b/compiler/rustc_metadata/src/lib.rs index 199aa9b5337a..6c6c60af063f 100644 --- a/compiler/rustc_metadata/src/lib.rs +++ b/compiler/rustc_metadata/src/lib.rs @@ -31,7 +31,6 @@ extern crate rustc_middle; extern crate tracing; pub use rmeta::provide; -use rustc_fluent_macro::fluent_messages; mod dependency_format; mod foreign_modules; @@ -47,4 +46,4 @@ pub use fs::{emit_wrapper_file, METADATA_FILENAME}; pub use native_libs::find_native_static_library; pub use rmeta::{encode_metadata, rendered_const, EncodedMetadata, METADATA_HEADER}; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_middle/src/lib.rs b/compiler/rustc_middle/src/lib.rs index 356092a49593..e048268fad12 100644 --- a/compiler/rustc_middle/src/lib.rs +++ b/compiler/rustc_middle/src/lib.rs @@ -77,8 +77,6 @@ extern crate tracing; #[macro_use] extern crate smallvec; -use rustc_fluent_macro::fluent_messages; - #[cfg(test)] mod tests; @@ -109,4 +107,4 @@ pub mod dep_graph; // Allows macros to refer to this crate as `::rustc_middle` extern crate self as rustc_middle; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_mir_build/src/lib.rs b/compiler/rustc_mir_build/src/lib.rs index 1f795b30fb79..8c4f0257da3e 100644 --- a/compiler/rustc_mir_build/src/lib.rs +++ b/compiler/rustc_mir_build/src/lib.rs @@ -24,9 +24,7 @@ mod thir; use rustc_middle::query::Providers; -use rustc_fluent_macro::fluent_messages; - -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { providers.check_match = thir::pattern::check_match; diff --git a/compiler/rustc_mir_dataflow/src/lib.rs b/compiler/rustc_mir_dataflow/src/lib.rs index 562ee42b25eb..d218f033d62d 100644 --- a/compiler/rustc_mir_dataflow/src/lib.rs +++ b/compiler/rustc_mir_dataflow/src/lib.rs @@ -13,7 +13,6 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; -use rustc_fluent_macro::fluent_messages; use rustc_middle::ty; pub use self::drop_flag_effects::{ @@ -39,7 +38,7 @@ pub mod storage; pub mod un_derefer; pub mod value_analysis; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub struct MoveDataParamEnv<'tcx> { pub move_data: MoveData<'tcx>, diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 5b8617875400..5c05446a981b 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -118,9 +118,7 @@ use rustc_const_eval::transform::promote_consts; use rustc_const_eval::transform::validate; use rustc_mir_dataflow::rustc_peek; -use rustc_fluent_macro::fluent_messages; - -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { check_unsafety::provide(providers); diff --git a/compiler/rustc_monomorphize/src/lib.rs b/compiler/rustc_monomorphize/src/lib.rs index 98c69fc700c8..2f5f2d15cd45 100644 --- a/compiler/rustc_monomorphize/src/lib.rs +++ b/compiler/rustc_monomorphize/src/lib.rs @@ -10,7 +10,6 @@ extern crate tracing; #[macro_use] extern crate rustc_middle; -use rustc_fluent_macro::fluent_messages; use rustc_hir::lang_items::LangItem; use rustc_middle::query::{Providers, TyCtxtAt}; use rustc_middle::traits; @@ -23,7 +22,7 @@ mod partitioning; mod polymorphize; mod util; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } fn custom_coerce_unsize_info<'tcx>( tcx: TyCtxtAt<'tcx>, diff --git a/compiler/rustc_parse/src/lib.rs b/compiler/rustc_parse/src/lib.rs index 7b9520bea50f..95352dbdc134 100644 --- a/compiler/rustc_parse/src/lib.rs +++ b/compiler/rustc_parse/src/lib.rs @@ -20,7 +20,6 @@ use rustc_ast::{AttrItem, Attribute, MetaItem}; use rustc_ast_pretty::pprust; use rustc_data_structures::sync::Lrc; use rustc_errors::{Diagnostic, FatalError, Level, PResult}; -use rustc_fluent_macro::fluent_messages; use rustc_session::parse::ParseSess; use rustc_span::{FileName, SourceFile, Span}; @@ -36,7 +35,7 @@ pub mod validate_attr; mod errors; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } // A bunch of utility functions of the form `parse__from_` // where includes crate, expr, item, stmt, tts, and one that diff --git a/compiler/rustc_passes/src/lib.rs b/compiler/rustc_passes/src/lib.rs index 68c31423b58b..4c4d5e58232d 100644 --- a/compiler/rustc_passes/src/lib.rs +++ b/compiler/rustc_passes/src/lib.rs @@ -23,7 +23,6 @@ extern crate rustc_middle; #[macro_use] extern crate tracing; -use rustc_fluent_macro::fluent_messages; use rustc_middle::query::Providers; pub mod abi_test; @@ -47,7 +46,7 @@ pub mod stability; mod upvars; mod weak_lang_items; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { check_attr::provide(providers); diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index d6d3f8286423..6d1771c81724 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -19,7 +19,6 @@ use rustc_ast::MacroDef; use rustc_attr as attr; use rustc_data_structures::fx::FxHashSet; use rustc_data_structures::intern::Interned; -use rustc_fluent_macro::fluent_messages; use rustc_hir as hir; use rustc_hir::def::{DefKind, Res}; use rustc_hir::def_id::{DefId, LocalDefId, LocalModDefId, CRATE_DEF_ID}; @@ -48,7 +47,7 @@ use errors::{ UnnamedItemIsPrivate, }; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } //////////////////////////////////////////////////////////////////////////////// /// Generic infrastructure used to implement specific visitors below. diff --git a/compiler/rustc_query_system/src/lib.rs b/compiler/rustc_query_system/src/lib.rs index 8e5e94291bd9..78930b151cd4 100644 --- a/compiler/rustc_query_system/src/lib.rs +++ b/compiler/rustc_query_system/src/lib.rs @@ -14,8 +14,6 @@ extern crate rustc_data_structures; #[macro_use] extern crate rustc_macros; -use rustc_fluent_macro::fluent_messages; - pub mod cache; pub mod dep_graph; mod error; @@ -28,4 +26,4 @@ pub use error::LayoutOfDepth; pub use error::QueryOverflow; pub use values::Value; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_resolve/src/lib.rs b/compiler/rustc_resolve/src/lib.rs index c131f70f087f..da396bd15d3f 100644 --- a/compiler/rustc_resolve/src/lib.rs +++ b/compiler/rustc_resolve/src/lib.rs @@ -40,7 +40,6 @@ use rustc_data_structures::sync::{FreezeReadGuard, Lrc}; use rustc_errors::{Applicability, DiagnosticBuilder, ErrorGuaranteed}; use rustc_expand::base::{DeriveResolutions, SyntaxExtension, SyntaxExtensionKind}; use rustc_feature::BUILTIN_ATTRIBUTES; -use rustc_fluent_macro::fluent_messages; use rustc_hir::def::Namespace::{self, *}; use rustc_hir::def::NonMacroAttrKind; use rustc_hir::def::{self, CtorOf, DefKind, DocLinkResMap, LifetimeRes, PartialRes, PerNS}; @@ -88,7 +87,7 @@ mod late; mod macros; pub mod rustdoc; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } #[derive(Debug)] enum Weak { diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index ea015fd3c683..ffc2a2506819 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -20,8 +20,6 @@ pub mod errors; #[macro_use] extern crate tracing; -use rustc_fluent_macro::fluent_messages; - pub mod utils; pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass}; pub use rustc_lint_defs as lint; @@ -45,7 +43,7 @@ pub use getopts; mod version; pub use version::RustcVersion; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } /// Requirements for a `StableHashingContext` to be used in this crate. /// This is a hack to allow using the `HashStable_Generic` derive macro diff --git a/compiler/rustc_trait_selection/src/lib.rs b/compiler/rustc_trait_selection/src/lib.rs index 536fdcb59dd1..de2577cca49e 100644 --- a/compiler/rustc_trait_selection/src/lib.rs +++ b/compiler/rustc_trait_selection/src/lib.rs @@ -37,11 +37,9 @@ extern crate rustc_middle; #[macro_use] extern crate smallvec; -use rustc_fluent_macro::fluent_messages; - pub mod errors; pub mod infer; pub mod solve; pub mod traits; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } diff --git a/compiler/rustc_ty_utils/src/lib.rs b/compiler/rustc_ty_utils/src/lib.rs index 7a99f95386c9..fa1f94e8b41e 100644 --- a/compiler/rustc_ty_utils/src/lib.rs +++ b/compiler/rustc_ty_utils/src/lib.rs @@ -24,7 +24,6 @@ extern crate rustc_middle; #[macro_use] extern crate tracing; -use rustc_fluent_macro::fluent_messages; use rustc_middle::query::Providers; mod abi; @@ -43,7 +42,7 @@ mod sig_types; mod structural_match; mod ty; -fluent_messages! { "../messages.ftl" } +rustc_fluent_macro::fluent_messages! { "../messages.ftl" } pub fn provide(providers: &mut Providers) { abi::provide(providers); diff --git a/tests/ui-fulldeps/fluent-messages/test.rs b/tests/ui-fulldeps/fluent-messages/test.rs index d19c6956cbdf..89ac48f36db5 100644 --- a/tests/ui-fulldeps/fluent-messages/test.rs +++ b/tests/ui-fulldeps/fluent-messages/test.rs @@ -4,7 +4,6 @@ #![crate_type = "lib"] extern crate rustc_errors; extern crate rustc_fluent_macro; -use rustc_fluent_macro::fluent_messages; /// Copy of the relevant `DiagnosticMessage` variant constructed by `fluent_messages` as it /// expects `crate::DiagnosticMessage` to exist. @@ -19,51 +18,37 @@ pub enum SubdiagnosticMessage { } mod missing_absolute { - use super::fluent_messages; - - fluent_messages! { "/definitely_does_not_exist.ftl" } + rustc_fluent_macro::fluent_messages! { "/definitely_does_not_exist.ftl" } //~^ ERROR could not open Fluent resource } mod missing_relative { - use super::fluent_messages; - - fluent_messages! { "../definitely_does_not_exist.ftl" } + rustc_fluent_macro::fluent_messages! { "../definitely_does_not_exist.ftl" } //~^ ERROR could not open Fluent resource } mod missing_message { - use super::fluent_messages; - - fluent_messages! { "./missing-message.ftl" } + rustc_fluent_macro::fluent_messages! { "./missing-message.ftl" } //~^ ERROR could not parse Fluent resource } mod duplicate { - use super::fluent_messages; - - fluent_messages! { "./duplicate.ftl" } + rustc_fluent_macro::fluent_messages! { "./duplicate.ftl" } //~^ ERROR overrides existing message: `no_crate_a_b_key` } mod slug_with_hyphens { - use super::fluent_messages; - - fluent_messages! { "./slug-with-hyphens.ftl" } + rustc_fluent_macro::fluent_messages! { "./slug-with-hyphens.ftl" } //~^ ERROR name `no_crate_this-slug-has-hyphens` contains a '-' character } mod label_with_hyphens { - use super::fluent_messages; - - fluent_messages! { "./label-with-hyphens.ftl" } + rustc_fluent_macro::fluent_messages! { "./label-with-hyphens.ftl" } //~^ ERROR attribute `label-has-hyphens` contains a '-' character } mod valid { - use super::fluent_messages; - - fluent_messages! { "./valid.ftl" } + rustc_fluent_macro::fluent_messages! { "./valid.ftl" } mod test_generated { use super::{fluent_generated::no_crate_key, DEFAULT_LOCALE_RESOURCE}; @@ -71,9 +56,7 @@ mod valid { } mod missing_crate_name { - use super::fluent_messages; - - fluent_messages! { "./missing-crate-name.ftl" } + rustc_fluent_macro::fluent_messages! { "./missing-crate-name.ftl" } //~^ ERROR name `no-crate_foo` contains a '-' character //~| ERROR name `with-hyphens` contains a '-' character //~| ERROR name `with-hyphens` does not start with the crate name @@ -87,16 +70,12 @@ mod missing_crate_name { } mod missing_message_ref { - use super::fluent_messages; - - fluent_messages! { "./missing-message-ref.ftl" } + rustc_fluent_macro::fluent_messages! { "./missing-message-ref.ftl" } //~^ ERROR referenced message `message` does not exist } mod bad_escape { - use super::fluent_messages; - - fluent_messages! { "./invalid-escape.ftl" } + rustc_fluent_macro::fluent_messages! { "./invalid-escape.ftl" } //~^ ERROR invalid escape `\n` //~| ERROR invalid escape `\"` //~| ERROR invalid escape `\'` diff --git a/tests/ui-fulldeps/fluent-messages/test.stderr b/tests/ui-fulldeps/fluent-messages/test.stderr index 2affe621c113..09d4a3847320 100644 --- a/tests/ui-fulldeps/fluent-messages/test.stderr +++ b/tests/ui-fulldeps/fluent-messages/test.stderr @@ -1,20 +1,20 @@ error: could not open Fluent resource: os-specific message - --> $DIR/test.rs:24:24 + --> $DIR/test.rs:21:44 | -LL | fluent_messages! { "/definitely_does_not_exist.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "/definitely_does_not_exist.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: could not open Fluent resource: os-specific message - --> $DIR/test.rs:31:24 + --> $DIR/test.rs:26:44 | -LL | fluent_messages! { "../definitely_does_not_exist.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "../definitely_does_not_exist.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: could not parse Fluent resource - --> $DIR/test.rs:38:24 + --> $DIR/test.rs:31:44 | -LL | fluent_messages! { "./missing-message.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "./missing-message.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^^ | = help: see additional errors emitted @@ -26,80 +26,80 @@ error: expected a message field for "no_crate_missing_message" | error: overrides existing message: `no_crate_a_b_key` - --> $DIR/test.rs:45:24 + --> $DIR/test.rs:36:44 | -LL | fluent_messages! { "./duplicate.ftl" } - | ^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "./duplicate.ftl" } + | ^^^^^^^^^^^^^^^^^ error: name `no_crate_this-slug-has-hyphens` contains a '-' character - --> $DIR/test.rs:52:24 + --> $DIR/test.rs:41:44 | -LL | fluent_messages! { "./slug-with-hyphens.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "./slug-with-hyphens.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: replace any '-'s with '_'s error: attribute `label-has-hyphens` contains a '-' character - --> $DIR/test.rs:59:24 + --> $DIR/test.rs:46:44 | -LL | fluent_messages! { "./label-with-hyphens.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "./label-with-hyphens.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: replace any '-'s with '_'s error: name `with-hyphens` contains a '-' character - --> $DIR/test.rs:76:24 + --> $DIR/test.rs:59:44 | -LL | fluent_messages! { "./missing-crate-name.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "./missing-crate-name.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: replace any '-'s with '_'s error: name `with-hyphens` does not start with the crate name - --> $DIR/test.rs:76:24 + --> $DIR/test.rs:59:44 | -LL | fluent_messages! { "./missing-crate-name.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "./missing-crate-name.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: prepend `no_crate_` to the slug name: `no_crate_with_hyphens` error: name `no-crate_foo` contains a '-' character - --> $DIR/test.rs:76:24 + --> $DIR/test.rs:59:44 | -LL | fluent_messages! { "./missing-crate-name.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "./missing-crate-name.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: replace any '-'s with '_'s error: referenced message `message` does not exist (in message `no_crate_missing_message_ref`) - --> $DIR/test.rs:92:24 + --> $DIR/test.rs:73:44 | -LL | fluent_messages! { "./missing-message-ref.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "./missing-message-ref.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ | = help: you may have meant to use a variable reference (`{$message}`) error: invalid escape `\n` in Fluent resource - --> $DIR/test.rs:99:24 + --> $DIR/test.rs:78:44 | -LL | fluent_messages! { "./invalid-escape.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "./invalid-escape.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: Fluent does not interpret these escape sequences () error: invalid escape `\"` in Fluent resource - --> $DIR/test.rs:99:24 + --> $DIR/test.rs:78:44 | -LL | fluent_messages! { "./invalid-escape.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "./invalid-escape.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: Fluent does not interpret these escape sequences () error: invalid escape `\'` in Fluent resource - --> $DIR/test.rs:99:24 + --> $DIR/test.rs:78:44 | -LL | fluent_messages! { "./invalid-escape.ftl" } - | ^^^^^^^^^^^^^^^^^^^^^^ +LL | rustc_fluent_macro::fluent_messages! { "./invalid-escape.ftl" } + | ^^^^^^^^^^^^^^^^^^^^^^ | = note: Fluent does not interpret these escape sequences () diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.rs b/tests/ui-fulldeps/internal-lints/diagnostics.rs index 994fc26ba021..7f545ead152c 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.rs +++ b/tests/ui-fulldeps/internal-lints/diagnostics.rs @@ -16,11 +16,10 @@ use rustc_errors::{ AddToDiagnostic, Diagnostic, DiagnosticBuilder, DiagnosticMessage, ErrorGuaranteed, Handler, IntoDiagnostic, SubdiagnosticMessage, }; -use rustc_fluent_macro::fluent_messages; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; -fluent_messages! { "./diagnostics.ftl" } +rustc_fluent_macro::fluent_messages! { "./diagnostics.ftl" } #[derive(Diagnostic)] #[diag(no_crate_example)] diff --git a/tests/ui-fulldeps/internal-lints/diagnostics.stderr b/tests/ui-fulldeps/internal-lints/diagnostics.stderr index 6e670c018520..8e0535e021be 100644 --- a/tests/ui-fulldeps/internal-lints/diagnostics.stderr +++ b/tests/ui-fulldeps/internal-lints/diagnostics.stderr @@ -1,5 +1,5 @@ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:43:17 + --> $DIR/diagnostics.rs:42:17 | LL | handler.struct_err("untranslatable diagnostic") | ^^^^^^^^^^ @@ -11,13 +11,13 @@ LL | #![deny(rustc::untranslatable_diagnostic)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:63:14 + --> $DIR/diagnostics.rs:62:14 | LL | diag.note("untranslatable diagnostic"); | ^^^^ error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls - --> $DIR/diagnostics.rs:80:25 + --> $DIR/diagnostics.rs:79:25 | LL | let _diag = handler.struct_err(crate::fluent_generated::no_crate_example); | ^^^^^^^^^^ @@ -29,13 +29,13 @@ LL | #![deny(rustc::diagnostic_outside_of_impl)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostics should only be created in `IntoDiagnostic`/`AddToDiagnostic` impls - --> $DIR/diagnostics.rs:83:25 + --> $DIR/diagnostics.rs:82:25 | LL | let _diag = handler.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ error: diagnostics should be created using translatable messages - --> $DIR/diagnostics.rs:83:25 + --> $DIR/diagnostics.rs:82:25 | LL | let _diag = handler.struct_err("untranslatable diagnostic"); | ^^^^^^^^^^ diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs index 283d87d3eb60..221f26f8edc4 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.rs @@ -20,11 +20,10 @@ extern crate rustc_session; extern crate rustc_span; use rustc_errors::{Applicability, DiagnosticMessage, SubdiagnosticMessage}; -use rustc_fluent_macro::fluent_messages; use rustc_macros::{Diagnostic, Subdiagnostic}; use rustc_span::Span; -fluent_messages! { "./example.ftl" } +rustc_fluent_macro::fluent_messages! { "./example.ftl" } struct NotIntoDiagnosticArg; diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr index 70d7b3225b59..bdcf54bd1904 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive-doc-comment-field.stderr @@ -1,5 +1,5 @@ error[E0277]: the trait bound `NotIntoDiagnosticArg: IntoDiagnosticArg` is not satisfied - --> $DIR/diagnostic-derive-doc-comment-field.rs:37:10 + --> $DIR/diagnostic-derive-doc-comment-field.rs:36:10 | LL | #[derive(Diagnostic)] | ---------- required by a bound introduced by this call @@ -13,7 +13,7 @@ note: required by a bound in `DiagnosticBuilder::<'a, G>::set_arg` = note: this error originates in the macro `forward` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `NotIntoDiagnosticArg: IntoDiagnosticArg` is not satisfied - --> $DIR/diagnostic-derive-doc-comment-field.rs:47:10 + --> $DIR/diagnostic-derive-doc-comment-field.rs:46:10 | LL | #[derive(Subdiagnostic)] | ------------- required by a bound introduced by this call diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs index c30120e5cf3a..63fb78ee9199 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.rs @@ -19,7 +19,6 @@ use rustc_span::Span; extern crate rustc_fluent_macro; extern crate rustc_macros; -use rustc_fluent_macro::fluent_messages; use rustc_macros::{Diagnostic, LintDiagnostic, Subdiagnostic}; extern crate rustc_middle; @@ -30,7 +29,7 @@ use rustc_errors::{Applicability, DiagnosticMessage, MultiSpan, SubdiagnosticMes extern crate rustc_session; -fluent_messages! { "./example.ftl" } +rustc_fluent_macro::fluent_messages! { "./example.ftl" } #[derive(Diagnostic)] #[diag(no_crate_example, code = "E0123")] diff --git a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr index 014cd5a73bd8..d8ba65d297e4 100644 --- a/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/diagnostic-derive.stderr @@ -1,11 +1,11 @@ error: unsupported type attribute for diagnostic derive enum - --> $DIR/diagnostic-derive.rs:44:1 + --> $DIR/diagnostic-derive.rs:43:1 | LL | #[diag(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:47:5 + --> $DIR/diagnostic-derive.rs:46:5 | LL | Foo, | ^^^ @@ -13,7 +13,7 @@ LL | Foo, = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:49:5 + --> $DIR/diagnostic-derive.rs:48:5 | LL | Bar, | ^^^ @@ -21,13 +21,13 @@ LL | Bar, = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[nonsense(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:60:1 + --> $DIR/diagnostic-derive.rs:59:1 | LL | #[nonsense(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:60:1 + --> $DIR/diagnostic-derive.rs:59:1 | LL | / #[nonsense(no_crate_example, code = "E0123")] LL | | @@ -39,7 +39,7 @@ LL | | struct InvalidStructAttr {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:67:1 + --> $DIR/diagnostic-derive.rs:66:1 | LL | / #[diag("E0123")] LL | | @@ -49,13 +49,13 @@ LL | | struct InvalidLitNestedAttr {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug must be the first argument - --> $DIR/diagnostic-derive.rs:77:16 + --> $DIR/diagnostic-derive.rs:76:16 | LL | #[diag(nonsense("foo"), code = "E0123", slug = "foo")] | ^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:77:1 + --> $DIR/diagnostic-derive.rs:76:1 | LL | / #[diag(nonsense("foo"), code = "E0123", slug = "foo")] LL | | @@ -66,7 +66,7 @@ LL | | struct InvalidNestedStructAttr1 {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: unknown argument - --> $DIR/diagnostic-derive.rs:83:8 + --> $DIR/diagnostic-derive.rs:82:8 | LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")] | ^^^^^^^^ @@ -74,7 +74,7 @@ LL | #[diag(nonsense = "...", code = "E0123", slug = "foo")] = note: only the `code` parameter is valid after the slug error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:83:1 + --> $DIR/diagnostic-derive.rs:82:1 | LL | / #[diag(nonsense = "...", code = "E0123", slug = "foo")] LL | | @@ -85,7 +85,7 @@ LL | | struct InvalidNestedStructAttr2 {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: unknown argument - --> $DIR/diagnostic-derive.rs:89:8 + --> $DIR/diagnostic-derive.rs:88:8 | LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")] | ^^^^^^^^ @@ -93,7 +93,7 @@ LL | #[diag(nonsense = 4, code = "E0123", slug = "foo")] = note: only the `code` parameter is valid after the slug error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:89:1 + --> $DIR/diagnostic-derive.rs:88:1 | LL | / #[diag(nonsense = 4, code = "E0123", slug = "foo")] LL | | @@ -104,7 +104,7 @@ LL | | struct InvalidNestedStructAttr3 {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: unknown argument - --> $DIR/diagnostic-derive.rs:95:42 + --> $DIR/diagnostic-derive.rs:94:42 | LL | #[diag(no_crate_example, code = "E0123", slug = "foo")] | ^^^^ @@ -112,55 +112,55 @@ LL | #[diag(no_crate_example, code = "E0123", slug = "foo")] = note: only the `code` parameter is valid after the slug error: `#[suggestion = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:102:5 + --> $DIR/diagnostic-derive.rs:101:5 | LL | #[suggestion = "bar"] | ^^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:109:8 - | -LL | #[diag(no_crate_example, code = "E0456")] - | ^^^^^^^^^^^^^^^^ - | -note: previously specified here --> $DIR/diagnostic-derive.rs:108:8 | +LL | #[diag(no_crate_example, code = "E0456")] + | ^^^^^^^^^^^^^^^^ + | +note: previously specified here + --> $DIR/diagnostic-derive.rs:107:8 + | LL | #[diag(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:109:26 + --> $DIR/diagnostic-derive.rs:108:26 | LL | #[diag(no_crate_example, code = "E0456")] | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:108:26 + --> $DIR/diagnostic-derive.rs:107:26 | LL | #[diag(no_crate_example, code = "E0123")] | ^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:115:42 + --> $DIR/diagnostic-derive.rs:114:42 | LL | #[diag(no_crate_example, code = "E0456", code = "E0457")] | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:115:26 + --> $DIR/diagnostic-derive.rs:114:26 | LL | #[diag(no_crate_example, code = "E0456", code = "E0457")] | ^^^^ error: diagnostic slug must be the first argument - --> $DIR/diagnostic-derive.rs:120:43 + --> $DIR/diagnostic-derive.rs:119:43 | LL | #[diag(no_crate_example, no_crate::example, code = "E0456")] | ^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:125:1 + --> $DIR/diagnostic-derive.rs:124:1 | LL | struct KindNotProvided {} | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -168,7 +168,7 @@ LL | struct KindNotProvided {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:128:1 + --> $DIR/diagnostic-derive.rs:127:1 | LL | / #[diag(code = "E0456")] LL | | @@ -178,31 +178,31 @@ LL | | struct SlugNotProvided {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:139:5 + --> $DIR/diagnostic-derive.rs:138:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: `#[nonsense]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:147:5 + --> $DIR/diagnostic-derive.rs:146:5 | LL | #[nonsense] | ^^^^^^^^^^^ error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:164:5 + --> $DIR/diagnostic-derive.rs:163:5 | LL | #[label(no_crate_label)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `name` doesn't refer to a field on this type - --> $DIR/diagnostic-derive.rs:172:46 + --> $DIR/diagnostic-derive.rs:171:46 | LL | #[suggestion(no_crate_suggestion, code = "{name}")] | ^^^^^^^^ error: invalid format string: expected `'}'` but string was terminated - --> $DIR/diagnostic-derive.rs:177:10 + --> $DIR/diagnostic-derive.rs:176:10 | LL | #[derive(Diagnostic)] | ^^^^^^^^^^ expected `'}'` in format string @@ -211,7 +211,7 @@ LL | #[derive(Diagnostic)] = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: invalid format string: unmatched `}` found - --> $DIR/diagnostic-derive.rs:187:10 + --> $DIR/diagnostic-derive.rs:186:10 | LL | #[derive(Diagnostic)] | ^^^^^^^^^^ unmatched `}` in format string @@ -220,19 +220,19 @@ LL | #[derive(Diagnostic)] = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error: the `#[label(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/diagnostic-derive.rs:207:5 + --> $DIR/diagnostic-derive.rs:206:5 | LL | #[label(no_crate_label)] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:226:5 + --> $DIR/diagnostic-derive.rs:225:5 | LL | #[suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid nested attribute - --> $DIR/diagnostic-derive.rs:234:18 + --> $DIR/diagnostic-derive.rs:233:18 | LL | #[suggestion(nonsense = "bar")] | ^^^^^^^^ @@ -240,13 +240,13 @@ LL | #[suggestion(nonsense = "bar")] = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:234:5 + --> $DIR/diagnostic-derive.rs:233:5 | LL | #[suggestion(nonsense = "bar")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid nested attribute - --> $DIR/diagnostic-derive.rs:243:18 + --> $DIR/diagnostic-derive.rs:242:18 | LL | #[suggestion(msg = "bar")] | ^^^ @@ -254,13 +254,13 @@ LL | #[suggestion(msg = "bar")] = help: only `no_span`, `style`, `code` and `applicability` are valid nested attributes error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:243:5 + --> $DIR/diagnostic-derive.rs:242:5 | LL | #[suggestion(msg = "bar")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^ error: wrong field type for suggestion - --> $DIR/diagnostic-derive.rs:266:5 + --> $DIR/diagnostic-derive.rs:265:5 | LL | / #[suggestion(no_crate_suggestion, code = "This is suggested code")] LL | | @@ -270,79 +270,79 @@ LL | | suggestion: Applicability, = help: `#[suggestion(...)]` should be applied to fields of type `Span` or `(Span, Applicability)` error: specified multiple times - --> $DIR/diagnostic-derive.rs:282:24 + --> $DIR/diagnostic-derive.rs:281:24 | LL | suggestion: (Span, Span, Applicability), | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:282:18 + --> $DIR/diagnostic-derive.rs:281:18 | LL | suggestion: (Span, Span, Applicability), | ^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:290:33 + --> $DIR/diagnostic-derive.rs:289:33 | LL | suggestion: (Applicability, Applicability, Span), | ^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:290:18 + --> $DIR/diagnostic-derive.rs:289:18 | LL | suggestion: (Applicability, Applicability, Span), | ^^^^^^^^^^^^^ error: `#[label = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:297:5 + --> $DIR/diagnostic-derive.rs:296:5 | LL | #[label = "bar"] | ^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/diagnostic-derive.rs:448:5 + --> $DIR/diagnostic-derive.rs:447:5 | LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "maybe-incorrect")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:450:24 + --> $DIR/diagnostic-derive.rs:449:24 | LL | suggestion: (Span, Applicability), | ^^^^^^^^^^^^^ error: invalid applicability - --> $DIR/diagnostic-derive.rs:456:69 + --> $DIR/diagnostic-derive.rs:455:69 | LL | #[suggestion(no_crate_suggestion, code = "...", applicability = "batman")] | ^^^^^^^^ error: the `#[help(...)]` attribute can only be applied to fields of type `Span`, `MultiSpan`, `bool` or `()` - --> $DIR/diagnostic-derive.rs:523:5 + --> $DIR/diagnostic-derive.rs:522:5 | LL | #[help(no_crate_help)] | ^^^^^^^^^^^^^^^^^^^^^^ error: a diagnostic slug must be the first argument to the attribute - --> $DIR/diagnostic-derive.rs:532:32 + --> $DIR/diagnostic-derive.rs:531:32 | LL | #[label(no_crate_label, foo)] | ^ error: only `no_span` is a valid nested attribute - --> $DIR/diagnostic-derive.rs:540:29 + --> $DIR/diagnostic-derive.rs:539:29 | LL | #[label(no_crate_label, foo = "...")] | ^^^ error: only `no_span` is a valid nested attribute - --> $DIR/diagnostic-derive.rs:548:29 + --> $DIR/diagnostic-derive.rs:547:29 | LL | #[label(no_crate_label, foo("..."))] | ^^^ error: `#[primary_span]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:560:5 + --> $DIR/diagnostic-derive.rs:559:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ @@ -350,13 +350,13 @@ LL | #[primary_span] = help: the `primary_span` field attribute is not valid for lint diagnostics error: `#[error(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:580:1 + --> $DIR/diagnostic-derive.rs:579:1 | LL | #[error(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:580:1 + --> $DIR/diagnostic-derive.rs:579:1 | LL | / #[error(no_crate_example, code = "E0123")] LL | | @@ -368,13 +368,13 @@ LL | | struct ErrorAttribute {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[warn_(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:587:1 + --> $DIR/diagnostic-derive.rs:586:1 | LL | #[warn_(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:587:1 + --> $DIR/diagnostic-derive.rs:586:1 | LL | / #[warn_(no_crate_example, code = "E0123")] LL | | @@ -386,13 +386,13 @@ LL | | struct WarnAttribute {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:594:1 + --> $DIR/diagnostic-derive.rs:593:1 | LL | #[lint(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:594:1 + --> $DIR/diagnostic-derive.rs:593:1 | LL | / #[lint(no_crate_example, code = "E0123")] LL | | @@ -404,13 +404,13 @@ LL | | struct LintAttributeOnSessionDiag {} = help: specify the slug as the first argument to the `#[diag(...)]` attribute, such as `#[diag(hir_analysis_example_error)]` error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:601:1 + --> $DIR/diagnostic-derive.rs:600:1 | LL | #[lint(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[lint(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:601:1 + --> $DIR/diagnostic-derive.rs:600:1 | LL | #[lint(no_crate_example, code = "E0123")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -418,7 +418,7 @@ LL | #[lint(no_crate_example, code = "E0123")] = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` error: diagnostic slug not specified - --> $DIR/diagnostic-derive.rs:601:1 + --> $DIR/diagnostic-derive.rs:600:1 | LL | / #[lint(no_crate_example, code = "E0123")] LL | | @@ -431,19 +431,19 @@ LL | | struct LintAttributeOnLintDiag {} = help: specify the slug as the first argument to the attribute, such as `#[diag(compiletest_example)]` error: specified multiple times - --> $DIR/diagnostic-derive.rs:611:53 + --> $DIR/diagnostic-derive.rs:610:53 | LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] | ^^^^ | note: previously specified here - --> $DIR/diagnostic-derive.rs:611:39 + --> $DIR/diagnostic-derive.rs:610:39 | LL | #[suggestion(no_crate_suggestion, code = "...", code = ",,,")] | ^^^^ error: wrong types for suggestion - --> $DIR/diagnostic-derive.rs:620:24 + --> $DIR/diagnostic-derive.rs:619:24 | LL | suggestion: (Span, usize), | ^^^^^ @@ -451,7 +451,7 @@ LL | suggestion: (Span, usize), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: wrong types for suggestion - --> $DIR/diagnostic-derive.rs:628:17 + --> $DIR/diagnostic-derive.rs:627:17 | LL | suggestion: (Span,), | ^^^^^^^ @@ -459,13 +459,13 @@ LL | suggestion: (Span,), = help: `#[suggestion(...)]` on a tuple field must be applied to fields of type `(Span, Applicability)` error: suggestion without `code = "..."` - --> $DIR/diagnostic-derive.rs:635:5 + --> $DIR/diagnostic-derive.rs:634:5 | LL | #[suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:642:1 + --> $DIR/diagnostic-derive.rs:641:1 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -473,7 +473,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] = help: consider creating a `Subdiagnostic` instead error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:645:1 + --> $DIR/diagnostic-derive.rs:644:1 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -481,7 +481,7 @@ LL | #[multipart_suggestion()] = help: consider creating a `Subdiagnostic` instead error: `#[multipart_suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:649:5 + --> $DIR/diagnostic-derive.rs:648:5 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -489,7 +489,7 @@ LL | #[multipart_suggestion(no_crate_suggestion)] = help: consider creating a `Subdiagnostic` instead error: `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:657:1 + --> $DIR/diagnostic-derive.rs:656:1 | LL | #[suggestion(no_crate_suggestion, code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -497,7 +497,7 @@ LL | #[suggestion(no_crate_suggestion, code = "...")] = help: `#[label]` and `#[suggestion]` can only be applied to fields error: `#[label]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:666:1 + --> $DIR/diagnostic-derive.rs:665:1 | LL | #[label] | ^^^^^^^^ @@ -505,31 +505,31 @@ LL | #[label] = help: `#[label]` and `#[suggestion]` can only be applied to fields error: `eager` is the only supported nested attribute for `subdiagnostic` - --> $DIR/diagnostic-derive.rs:700:7 + --> $DIR/diagnostic-derive.rs:699:7 | LL | #[subdiagnostic(bad)] | ^^^^^^^^^^^^^^^^^^ error: `#[subdiagnostic = ...]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:708:5 + --> $DIR/diagnostic-derive.rs:707:5 | LL | #[subdiagnostic = "bad"] | ^^^^^^^^^^^^^^^^^^^^^^^^ error: `eager` is the only supported nested attribute for `subdiagnostic` - --> $DIR/diagnostic-derive.rs:716:7 + --> $DIR/diagnostic-derive.rs:715:7 | LL | #[subdiagnostic(bad, bad)] | ^^^^^^^^^^^^^^^^^^^^^^^ error: `eager` is the only supported nested attribute for `subdiagnostic` - --> $DIR/diagnostic-derive.rs:724:7 + --> $DIR/diagnostic-derive.rs:723:7 | LL | #[subdiagnostic("bad")] | ^^^^^^^^^^^^^^^^^^^^ error: `#[subdiagnostic(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:732:5 + --> $DIR/diagnostic-derive.rs:731:5 | LL | #[subdiagnostic(eager)] | ^^^^^^^^^^^^^^^^^^^^^^^ @@ -537,19 +537,19 @@ LL | #[subdiagnostic(eager)] = help: eager subdiagnostics are not supported on lints error: expected at least one string literal for `code(...)` - --> $DIR/diagnostic-derive.rs:790:23 + --> $DIR/diagnostic-derive.rs:789:23 | LL | #[suggestion(code())] | ^ error: `code(...)` must contain only string literals - --> $DIR/diagnostic-derive.rs:798:23 + --> $DIR/diagnostic-derive.rs:797:23 | LL | #[suggestion(code(foo))] | ^^^ error: `#[suggestion(...)]` is not a valid attribute - --> $DIR/diagnostic-derive.rs:822:5 + --> $DIR/diagnostic-derive.rs:821:5 | LL | #[suggestion(no_crate_suggestion, code = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -559,85 +559,85 @@ LL | #[suggestion(no_crate_suggestion, code = "")] = help: to show a variable set of suggestions, use a `Vec` of `Subdiagnostic`s annotated with `#[suggestion(...)]` error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/diagnostic-derive.rs:55:8 + --> $DIR/diagnostic-derive.rs:54:8 | LL | #[diag = "E0123"] | ^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/diagnostic-derive.rs:798:23 + --> $DIR/diagnostic-derive.rs:797:23 | LL | #[suggestion(code(foo))] | ^^^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/diagnostic-derive.rs:807:25 + --> $DIR/diagnostic-derive.rs:806:25 | LL | #[suggestion(code = 3)] | ^ maybe a missing crate `core`? error: cannot find attribute `nonsense` in this scope - --> $DIR/diagnostic-derive.rs:60:3 + --> $DIR/diagnostic-derive.rs:59:3 | LL | #[nonsense(no_crate_example, code = "E0123")] | ^^^^^^^^ error: cannot find attribute `nonsense` in this scope - --> $DIR/diagnostic-derive.rs:147:7 + --> $DIR/diagnostic-derive.rs:146:7 | LL | #[nonsense] | ^^^^^^^^ error: cannot find attribute `error` in this scope - --> $DIR/diagnostic-derive.rs:580:3 + --> $DIR/diagnostic-derive.rs:579:3 | LL | #[error(no_crate_example, code = "E0123")] | ^^^^^ error: cannot find attribute `warn_` in this scope - --> $DIR/diagnostic-derive.rs:587:3 + --> $DIR/diagnostic-derive.rs:586:3 | LL | #[warn_(no_crate_example, code = "E0123")] | ^^^^^ help: a built-in attribute with a similar name exists: `warn` error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive.rs:594:3 + --> $DIR/diagnostic-derive.rs:593:3 | LL | #[lint(no_crate_example, code = "E0123")] | ^^^^ help: a built-in attribute with a similar name exists: `link` error: cannot find attribute `lint` in this scope - --> $DIR/diagnostic-derive.rs:601:3 + --> $DIR/diagnostic-derive.rs:600:3 | LL | #[lint(no_crate_example, code = "E0123")] | ^^^^ help: a built-in attribute with a similar name exists: `link` error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:642:3 + --> $DIR/diagnostic-derive.rs:641:3 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:645:3 + --> $DIR/diagnostic-derive.rs:644:3 | LL | #[multipart_suggestion()] | ^^^^^^^^^^^^^^^^^^^^ error: cannot find attribute `multipart_suggestion` in this scope - --> $DIR/diagnostic-derive.rs:649:7 + --> $DIR/diagnostic-derive.rs:648:7 | LL | #[multipart_suggestion(no_crate_suggestion)] | ^^^^^^^^^^^^^^^^^^^^ error[E0425]: cannot find value `nonsense` in module `crate::fluent_generated` - --> $DIR/diagnostic-derive.rs:72:8 + --> $DIR/diagnostic-derive.rs:71:8 | LL | #[diag(nonsense, code = "E0123")] | ^^^^^^^^ not found in `crate::fluent_generated` error[E0425]: cannot find value `__code_34` in this scope - --> $DIR/diagnostic-derive.rs:804:10 + --> $DIR/diagnostic-derive.rs:803:10 | LL | #[derive(Diagnostic)] | ^^^^^^^^^^ not found in this scope @@ -645,7 +645,7 @@ LL | #[derive(Diagnostic)] = note: this error originates in the derive macro `Diagnostic` (in Nightly builds, run with -Z macro-backtrace for more info) error[E0277]: the trait bound `Hello: IntoDiagnosticArg` is not satisfied - --> $DIR/diagnostic-derive.rs:346:12 + --> $DIR/diagnostic-derive.rs:345:12 | LL | #[derive(Diagnostic)] | ---------- required by a bound introduced by this call diff --git a/tests/ui-fulldeps/session-diagnostic/invalid-variable.rs b/tests/ui-fulldeps/session-diagnostic/invalid-variable.rs index 57798dda3eb2..2ec07fa14203 100644 --- a/tests/ui-fulldeps/session-diagnostic/invalid-variable.rs +++ b/tests/ui-fulldeps/session-diagnostic/invalid-variable.rs @@ -9,12 +9,11 @@ extern crate rustc_driver; extern crate rustc_fluent_macro; extern crate rustc_macros; extern crate rustc_errors; -use rustc_fluent_macro::fluent_messages; use rustc_macros::Diagnostic; use rustc_errors::{SubdiagnosticMessage, DiagnosticMessage}; extern crate rustc_session; -fluent_messages! { "./example.ftl" } +rustc_fluent_macro::fluent_messages! { "./example.ftl" } #[derive(Diagnostic)] #[diag(no_crate_bad_reference)] diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs index dd0f7a7efb71..74cf91db7a7c 100644 --- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs +++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.rs @@ -18,11 +18,10 @@ extern crate rustc_session; extern crate rustc_span; use rustc_errors::{Applicability, DiagnosticMessage, SubdiagnosticMessage}; -use rustc_fluent_macro::fluent_messages; use rustc_macros::Subdiagnostic; use rustc_span::Span; -fluent_messages! { "./example.ftl" } +rustc_fluent_macro::fluent_messages! { "./example.ftl" } #[derive(Subdiagnostic)] #[label(no_crate_example)] diff --git a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr index 1f267aceb9ef..80bee3bd6e6c 100644 --- a/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr +++ b/tests/ui-fulldeps/session-diagnostic/subdiagnostic-derive.stderr @@ -1,5 +1,5 @@ error: label without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:52:1 + --> $DIR/subdiagnostic-derive.rs:51:1 | LL | / #[label(no_crate_example)] LL | | @@ -9,127 +9,127 @@ LL | | } | |_^ error: diagnostic slug must be first argument of a `#[label(...)]` attribute - --> $DIR/subdiagnostic-derive.rs:59:1 + --> $DIR/subdiagnostic-derive.rs:58:1 | LL | #[label] | ^^^^^^^^ error: `#[foo]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:68:1 + --> $DIR/subdiagnostic-derive.rs:67:1 | LL | #[foo] | ^^^^^^ error: `#[label = ...]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:78:1 + --> $DIR/subdiagnostic-derive.rs:77:1 | LL | #[label = "..."] | ^^^^^^^^^^^^^^^^ error: only `no_span` is a valid nested attribute - --> $DIR/subdiagnostic-derive.rs:87:9 + --> $DIR/subdiagnostic-derive.rs:86:9 | LL | #[label(bug = "...")] | ^^^ error: diagnostic slug must be first argument of a `#[label(...)]` attribute - --> $DIR/subdiagnostic-derive.rs:87:1 + --> $DIR/subdiagnostic-derive.rs:86:1 | LL | #[label(bug = "...")] | ^^^^^^^^^^^^^^^^^^^^^ error: only `no_span` is a valid nested attribute - --> $DIR/subdiagnostic-derive.rs:107:9 + --> $DIR/subdiagnostic-derive.rs:106:9 | LL | #[label(slug = 4)] | ^^^^ error: diagnostic slug must be first argument of a `#[label(...)]` attribute - --> $DIR/subdiagnostic-derive.rs:107:1 + --> $DIR/subdiagnostic-derive.rs:106:1 | LL | #[label(slug = 4)] | ^^^^^^^^^^^^^^^^^^ error: only `no_span` is a valid nested attribute - --> $DIR/subdiagnostic-derive.rs:117:9 + --> $DIR/subdiagnostic-derive.rs:116:9 | LL | #[label(slug("..."))] | ^^^^ error: diagnostic slug must be first argument of a `#[label(...)]` attribute - --> $DIR/subdiagnostic-derive.rs:117:1 + --> $DIR/subdiagnostic-derive.rs:116:1 | LL | #[label(slug("..."))] | ^^^^^^^^^^^^^^^^^^^^^ error: diagnostic slug must be first argument of a `#[label(...)]` attribute - --> $DIR/subdiagnostic-derive.rs:137:1 + --> $DIR/subdiagnostic-derive.rs:136:1 | LL | #[label()] | ^^^^^^^^^^ error: only `no_span` is a valid nested attribute - --> $DIR/subdiagnostic-derive.rs:146:27 + --> $DIR/subdiagnostic-derive.rs:145:27 | LL | #[label(no_crate_example, code = "...")] | ^^^^ error: only `no_span` is a valid nested attribute - --> $DIR/subdiagnostic-derive.rs:155:27 + --> $DIR/subdiagnostic-derive.rs:154:27 | LL | #[label(no_crate_example, applicability = "machine-applicable")] | ^^^^^^^^^^^^^ error: unsupported type attribute for subdiagnostic enum - --> $DIR/subdiagnostic-derive.rs:164:1 + --> $DIR/subdiagnostic-derive.rs:163:1 | LL | #[foo] | ^^^^^^ error: `#[bar]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:178:5 + --> $DIR/subdiagnostic-derive.rs:177:5 | LL | #[bar] | ^^^^^^ error: `#[bar = ...]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:190:5 + --> $DIR/subdiagnostic-derive.rs:189:5 | LL | #[bar = "..."] | ^^^^^^^^^^^^^^ error: `#[bar = ...]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:202:5 + --> $DIR/subdiagnostic-derive.rs:201:5 | LL | #[bar = 4] | ^^^^^^^^^^ error: `#[bar(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:214:5 + --> $DIR/subdiagnostic-derive.rs:213:5 | LL | #[bar("...")] | ^^^^^^^^^^^^^ error: only `no_span` is a valid nested attribute - --> $DIR/subdiagnostic-derive.rs:226:13 + --> $DIR/subdiagnostic-derive.rs:225:13 | LL | #[label(code = "...")] | ^^^^ error: diagnostic slug must be first argument of a `#[label(...)]` attribute - --> $DIR/subdiagnostic-derive.rs:226:5 + --> $DIR/subdiagnostic-derive.rs:225:5 | LL | #[label(code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^ error: the `#[primary_span]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive.rs:255:5 + --> $DIR/subdiagnostic-derive.rs:254:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: label without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:252:1 + --> $DIR/subdiagnostic-derive.rs:251:1 | LL | / #[label(no_crate_example)] LL | | @@ -141,13 +141,13 @@ LL | | } | |_^ error: `#[applicability]` is only valid on suggestions - --> $DIR/subdiagnostic-derive.rs:265:5 + --> $DIR/subdiagnostic-derive.rs:264:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: `#[bar]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:275:5 + --> $DIR/subdiagnostic-derive.rs:274:5 | LL | #[bar] | ^^^^^^ @@ -155,13 +155,13 @@ LL | #[bar] = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes error: `#[bar = ...]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:286:5 + --> $DIR/subdiagnostic-derive.rs:285:5 | LL | #[bar = "..."] | ^^^^^^^^^^^^^^ error: `#[bar(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:297:5 + --> $DIR/subdiagnostic-derive.rs:296:5 | LL | #[bar("...")] | ^^^^^^^^^^^^^ @@ -169,73 +169,73 @@ LL | #[bar("...")] = help: only `primary_span`, `applicability` and `skip_arg` are valid field attributes error: a diagnostic slug must be the first argument to the attribute - --> $DIR/subdiagnostic-derive.rs:329:44 + --> $DIR/subdiagnostic-derive.rs:328:44 | LL | #[label(no_crate_example, no_crate::example)] | ^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:342:5 + --> $DIR/subdiagnostic-derive.rs:341:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:339:5 + --> $DIR/subdiagnostic-derive.rs:338:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ error: subdiagnostic kind not specified - --> $DIR/subdiagnostic-derive.rs:348:8 + --> $DIR/subdiagnostic-derive.rs:347:8 | LL | struct AG { | ^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:385:46 + --> $DIR/subdiagnostic-derive.rs:384:46 | LL | #[suggestion(no_crate_example, code = "...", code = "...")] | ^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:385:32 + --> $DIR/subdiagnostic-derive.rs:384:32 | LL | #[suggestion(no_crate_example, code = "...", code = "...")] | ^^^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:403:5 + --> $DIR/subdiagnostic-derive.rs:402:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:400:5 + --> $DIR/subdiagnostic-derive.rs:399:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: the `#[applicability]` attribute can only be applied to fields of type `Applicability` - --> $DIR/subdiagnostic-derive.rs:413:5 + --> $DIR/subdiagnostic-derive.rs:412:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: suggestion without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:426:1 + --> $DIR/subdiagnostic-derive.rs:425:1 | LL | #[suggestion(no_crate_example)] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: invalid applicability - --> $DIR/subdiagnostic-derive.rs:436:62 + --> $DIR/subdiagnostic-derive.rs:435:62 | LL | #[suggestion(no_crate_example, code = "...", applicability = "foo")] | ^^^^^ error: suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:454:1 + --> $DIR/subdiagnostic-derive.rs:453:1 | LL | / #[suggestion(no_crate_example, code = "...")] LL | | @@ -245,25 +245,25 @@ LL | | } | |_^ error: unsupported type attribute for subdiagnostic enum - --> $DIR/subdiagnostic-derive.rs:468:1 + --> $DIR/subdiagnostic-derive.rs:467:1 | LL | #[label] | ^^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:488:39 + --> $DIR/subdiagnostic-derive.rs:487:39 | LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")] | ^^^^^^^ error: `var` doesn't refer to a field on this type - --> $DIR/subdiagnostic-derive.rs:507:43 + --> $DIR/subdiagnostic-derive.rs:506:43 | LL | #[suggestion(no_crate_example, code = "{var}", applicability = "machine-applicable")] | ^^^^^^^ error: `#[suggestion_part]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:530:5 + --> $DIR/subdiagnostic-derive.rs:529:5 | LL | #[suggestion_part] | ^^^^^^^^^^^^^^^^^^ @@ -271,7 +271,7 @@ LL | #[suggestion_part] = help: `#[suggestion_part(...)]` is only valid in multipart suggestions, use `#[primary_span]` instead error: `#[suggestion_part(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:533:5 + --> $DIR/subdiagnostic-derive.rs:532:5 | LL | #[suggestion_part(code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -279,7 +279,7 @@ LL | #[suggestion_part(code = "...")] = help: `#[suggestion_part(...)]` is only valid in multipart suggestions error: suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:527:1 + --> $DIR/subdiagnostic-derive.rs:526:1 | LL | / #[suggestion(no_crate_example, code = "...")] LL | | @@ -291,7 +291,7 @@ LL | | } | |_^ error: invalid nested attribute - --> $DIR/subdiagnostic-derive.rs:542:42 + --> $DIR/subdiagnostic-derive.rs:541:42 | LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")] | ^^^^ @@ -299,7 +299,7 @@ LL | #[multipart_suggestion(no_crate_example, code = "...", applicability = "mac = help: only `no_span`, `style` and `applicability` are valid nested attributes error: multipart suggestion without any `#[suggestion_part(...)]` fields - --> $DIR/subdiagnostic-derive.rs:542:1 + --> $DIR/subdiagnostic-derive.rs:541:1 | LL | / #[multipart_suggestion(no_crate_example, code = "...", applicability = "machine-applicable")] LL | | @@ -310,19 +310,19 @@ LL | | } | |_^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:552:5 + --> $DIR/subdiagnostic-derive.rs:551:5 | LL | #[suggestion_part] | ^^^^^^^^^^^^^^^^^^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:560:5 + --> $DIR/subdiagnostic-derive.rs:559:5 | LL | #[suggestion_part()] | ^^^^^^^^^^^^^^^^^^^^ error: `#[primary_span]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:569:5 + --> $DIR/subdiagnostic-derive.rs:568:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ @@ -330,7 +330,7 @@ LL | #[primary_span] = help: multipart suggestions use one or more `#[suggestion_part]`s rather than one `#[primary_span]` error: multipart suggestion without any `#[suggestion_part(...)]` fields - --> $DIR/subdiagnostic-derive.rs:566:1 + --> $DIR/subdiagnostic-derive.rs:565:1 | LL | / #[multipart_suggestion(no_crate_example)] LL | | @@ -342,91 +342,91 @@ LL | | } | |_^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:577:5 + --> $DIR/subdiagnostic-derive.rs:576:5 | LL | #[suggestion_part] | ^^^^^^^^^^^^^^^^^^ error: `#[suggestion_part(...)]` attribute without `code = "..."` - --> $DIR/subdiagnostic-derive.rs:580:5 + --> $DIR/subdiagnostic-derive.rs:579:5 | LL | #[suggestion_part()] | ^^^^^^^^^^^^^^^^^^^^ error: `code` is the only valid nested attribute - --> $DIR/subdiagnostic-derive.rs:583:23 + --> $DIR/subdiagnostic-derive.rs:582:23 | LL | #[suggestion_part(foo = "bar")] | ^^^ error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive.rs:588:5 + --> $DIR/subdiagnostic-derive.rs:587:5 | LL | #[suggestion_part(code = "...")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: the `#[suggestion_part(...)]` attribute can only be applied to fields of type `Span` or `MultiSpan` - --> $DIR/subdiagnostic-derive.rs:591:5 + --> $DIR/subdiagnostic-derive.rs:590:5 | LL | #[suggestion_part()] | ^^^^^^^^^^^^^^^^^^^^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:599:37 + --> $DIR/subdiagnostic-derive.rs:598:37 | LL | #[suggestion_part(code = "...", code = ",,,")] | ^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:599:23 + --> $DIR/subdiagnostic-derive.rs:598:23 | LL | #[suggestion_part(code = "...", code = ",,,")] | ^^^^ error: `#[applicability]` has no effect if all `#[suggestion]`/`#[multipart_suggestion]` attributes have a static `applicability = "..."` - --> $DIR/subdiagnostic-derive.rs:628:5 + --> $DIR/subdiagnostic-derive.rs:627:5 | LL | #[applicability] | ^^^^^^^^^^^^^^^^ error: expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive.rs:676:34 + --> $DIR/subdiagnostic-derive.rs:675:34 | LL | #[suggestion_part(code("foo"))] | ^ error: expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive.rs:687:41 + --> $DIR/subdiagnostic-derive.rs:686:41 | LL | #[suggestion_part(code("foo", "bar"))] | ^ error: expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive.rs:698:30 + --> $DIR/subdiagnostic-derive.rs:697:30 | LL | #[suggestion_part(code(3))] | ^ error: expected exactly one string literal for `code = ...` - --> $DIR/subdiagnostic-derive.rs:709:29 + --> $DIR/subdiagnostic-derive.rs:708:29 | LL | #[suggestion_part(code())] | ^ error: specified multiple times - --> $DIR/subdiagnostic-derive.rs:764:1 + --> $DIR/subdiagnostic-derive.rs:763:1 | LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ | note: previously specified here - --> $DIR/subdiagnostic-derive.rs:764:1 + --> $DIR/subdiagnostic-derive.rs:763:1 | LL | #[suggestion(no_crate_example, code = "", style = "hidden", style = "normal")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error: `#[suggestion_hidden(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:773:1 + --> $DIR/subdiagnostic-derive.rs:772:1 | LL | #[suggestion_hidden(no_crate_example, code = "")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -434,7 +434,7 @@ LL | #[suggestion_hidden(no_crate_example, code = "")] = help: Use `#[suggestion(..., style = "hidden")]` instead error: `#[suggestion_hidden(...)]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:781:1 + --> $DIR/subdiagnostic-derive.rs:780:1 | LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")] | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ @@ -442,7 +442,7 @@ LL | #[suggestion_hidden(no_crate_example, code = "", style = "normal")] = help: Use `#[suggestion(..., style = "hidden")]` instead error: invalid suggestion style - --> $DIR/subdiagnostic-derive.rs:789:51 + --> $DIR/subdiagnostic-derive.rs:788:51 | LL | #[suggestion(no_crate_example, code = "", style = "foo")] | ^^^^^ @@ -450,25 +450,25 @@ LL | #[suggestion(no_crate_example, code = "", style = "foo")] = help: valid styles are `normal`, `short`, `hidden`, `verbose` and `tool-only` error: expected `= "xxx"` - --> $DIR/subdiagnostic-derive.rs:797:49 + --> $DIR/subdiagnostic-derive.rs:796:49 | LL | #[suggestion(no_crate_example, code = "", style = 42)] | ^ error: a diagnostic slug must be the first argument to the attribute - --> $DIR/subdiagnostic-derive.rs:805:48 + --> $DIR/subdiagnostic-derive.rs:804:48 | LL | #[suggestion(no_crate_example, code = "", style)] | ^ error: expected `= "xxx"` - --> $DIR/subdiagnostic-derive.rs:813:48 + --> $DIR/subdiagnostic-derive.rs:812:48 | LL | #[suggestion(no_crate_example, code = "", style("foo"))] | ^ error: `#[primary_span]` is not a valid attribute - --> $DIR/subdiagnostic-derive.rs:826:5 + --> $DIR/subdiagnostic-derive.rs:825:5 | LL | #[primary_span] | ^^^^^^^^^^^^^^^ @@ -477,7 +477,7 @@ LL | #[primary_span] = help: to create a suggestion with multiple spans, use `#[multipart_suggestion]` instead error: suggestion without `#[primary_span]` field - --> $DIR/subdiagnostic-derive.rs:823:1 + --> $DIR/subdiagnostic-derive.rs:822:1 | LL | / #[suggestion(no_crate_example, code = "")] LL | | @@ -489,115 +489,115 @@ LL | | } | |_^ error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/subdiagnostic-derive.rs:97:9 + --> $DIR/subdiagnostic-derive.rs:96:9 | LL | #[label("...")] | ^^^^^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/subdiagnostic-derive.rs:313:1 + --> $DIR/subdiagnostic-derive.rs:312:1 | LL | union AC { | ^^^^^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/subdiagnostic-derive.rs:583:27 + --> $DIR/subdiagnostic-derive.rs:582:27 | LL | #[suggestion_part(foo = "bar")] | ^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/subdiagnostic-derive.rs:676:28 + --> $DIR/subdiagnostic-derive.rs:675:28 | LL | #[suggestion_part(code("foo"))] | ^^^^^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/subdiagnostic-derive.rs:687:28 + --> $DIR/subdiagnostic-derive.rs:686:28 | LL | #[suggestion_part(code("foo", "bar"))] | ^^^^^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/subdiagnostic-derive.rs:698:28 + --> $DIR/subdiagnostic-derive.rs:697:28 | LL | #[suggestion_part(code(3))] | ^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/subdiagnostic-derive.rs:721:30 + --> $DIR/subdiagnostic-derive.rs:720:30 | LL | #[suggestion_part(code = 3)] | ^ maybe a missing crate `core`? error[E0433]: failed to resolve: maybe a missing crate `core`? - --> $DIR/subdiagnostic-derive.rs:813:48 + --> $DIR/subdiagnostic-derive.rs:812:48 | LL | #[suggestion(no_crate_example, code = "", style("foo"))] | ^ maybe a missing crate `core`? error: cannot find attribute `foo` in this scope - --> $DIR/subdiagnostic-derive.rs:68:3 + --> $DIR/subdiagnostic-derive.rs:67:3 | LL | #[foo] | ^^^ error: cannot find attribute `foo` in this scope - --> $DIR/subdiagnostic-derive.rs:164:3 + --> $DIR/subdiagnostic-derive.rs:163:3 | LL | #[foo] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:178:7 + --> $DIR/subdiagnostic-derive.rs:177:7 | LL | #[bar] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:190:7 + --> $DIR/subdiagnostic-derive.rs:189:7 | LL | #[bar = "..."] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:202:7 + --> $DIR/subdiagnostic-derive.rs:201:7 | LL | #[bar = 4] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:214:7 + --> $DIR/subdiagnostic-derive.rs:213:7 | LL | #[bar("...")] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:275:7 + --> $DIR/subdiagnostic-derive.rs:274:7 | LL | #[bar] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:286:7 + --> $DIR/subdiagnostic-derive.rs:285:7 | LL | #[bar = "..."] | ^^^ error: cannot find attribute `bar` in this scope - --> $DIR/subdiagnostic-derive.rs:297:7 + --> $DIR/subdiagnostic-derive.rs:296:7 | LL | #[bar("...")] | ^^^ error[E0425]: cannot find value `slug` in module `crate::fluent_generated` - --> $DIR/subdiagnostic-derive.rs:127:9 + --> $DIR/subdiagnostic-derive.rs:126:9 | LL | #[label(slug)] | ^^^^ not found in `crate::fluent_generated` error[E0425]: cannot find value `__code_29` in this scope - --> $DIR/subdiagnostic-derive.rs:715:10 + --> $DIR/subdiagnostic-derive.rs:714:10 | LL | #[derive(Subdiagnostic)] | ^^^^^^^^^^^^^ not found in this scope From af3fbb3607316d60ace206d53294cf3cdc5c9f48 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 22 Nov 2023 10:39:44 +1100 Subject: [PATCH 72/93] Remove unnecessary dependencies. --- Cargo.lock | 2 -- compiler/rustc_driver_impl/Cargo.toml | 1 - compiler/rustc_hir/Cargo.toml | 1 - 3 files changed, 4 deletions(-) diff --git a/Cargo.lock b/Cargo.lock index 744c91a4aa24..fa150b06b86a 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3716,7 +3716,6 @@ dependencies = [ "rustc_const_eval", "rustc_data_structures", "rustc_error_codes", - "rustc_error_messages", "rustc_errors", "rustc_expand", "rustc_feature", @@ -3868,7 +3867,6 @@ dependencies = [ "rustc_arena", "rustc_ast", "rustc_data_structures", - "rustc_error_messages", "rustc_index", "rustc_macros", "rustc_serialize", diff --git a/compiler/rustc_driver_impl/Cargo.toml b/compiler/rustc_driver_impl/Cargo.toml index 545ff32e598a..f2a8c54b6d54 100644 --- a/compiler/rustc_driver_impl/Cargo.toml +++ b/compiler/rustc_driver_impl/Cargo.toml @@ -16,7 +16,6 @@ rustc_codegen_ssa = { path = "../rustc_codegen_ssa" } rustc_const_eval = { path = "../rustc_const_eval" } rustc_data_structures = { path = "../rustc_data_structures" } rustc_error_codes = { path = "../rustc_error_codes" } -rustc_error_messages = { path = "../rustc_error_messages" } rustc_errors = { path = "../rustc_errors" } rustc_expand = { path = "../rustc_expand" } rustc_feature = { path = "../rustc_feature" } diff --git a/compiler/rustc_hir/Cargo.toml b/compiler/rustc_hir/Cargo.toml index a72c4d0f18bc..ac24c47d0b79 100644 --- a/compiler/rustc_hir/Cargo.toml +++ b/compiler/rustc_hir/Cargo.toml @@ -9,7 +9,6 @@ odht = { version = "0.3.1", features = ["nightly"] } rustc_arena = { path = "../rustc_arena" } rustc_ast = { path = "../rustc_ast" } rustc_data_structures = { path = "../rustc_data_structures" } -rustc_error_messages = { path = "../rustc_error_messages" } rustc_index = { path = "../rustc_index" } rustc_macros = { path = "../rustc_macros" } rustc_serialize = { path = "../rustc_serialize" } From 54ee79b3b8c2d2cb62ec5359e9d226083dc6628c Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 23 Nov 2023 06:27:22 +0000 Subject: [PATCH 73/93] Remove unused ObligationCauseCode::ProjectionWf --- compiler/rustc_middle/src/traits/mod.rs | 3 --- .../src/traits/error_reporting/suggestions.rs | 3 --- 2 files changed, 6 deletions(-) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 1ccd6fb56d9c..bda229c12631 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -250,9 +250,6 @@ pub enum ObligationCauseCode<'tcx> { /// A tuple is WF only if its middle elements are `Sized`. TupleElem, - /// This is the trait reference from the given projection. - ProjectionWf(ty::AliasTy<'tcx>), - /// Must satisfy all of the where-clause predicates of the /// given item. ItemObligation(DefId), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index e260fcd5e756..4282f42a2b13 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2621,9 +2621,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::TupleElem => { err.note("only the last element of a tuple may have a dynamically sized type"); } - ObligationCauseCode::ProjectionWf(data) => { - err.note(format!("required so that the projection `{data}` is well-formed")); - } ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { err.note(format!( "required so that reference `{ref_ty}` does not outlive its referent" From 0f9ab6371d6ded2aec6bcfbc17279485b855f0f7 Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 23 Nov 2023 06:27:47 +0000 Subject: [PATCH 74/93] Remove some lifetime-only ObligationCauseCode notes --- .../src/traits/error_reporting/suggestions.rs | 14 +++----------- 1 file changed, 3 insertions(+), 11 deletions(-) diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 4282f42a2b13..47eaca90d1bc 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2607,7 +2607,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::BinOp { .. } | ObligationCauseCode::AscribeUserTypeProvePredicate(..) | ObligationCauseCode::DropImpl - | ObligationCauseCode::ConstParam(_) => {} + | ObligationCauseCode::ConstParam(_) + | ObligationCauseCode::ReferenceOutlivesReferent(..) + | ObligationCauseCode::ObjectTypeBound(..) => {} ObligationCauseCode::RustCall => { if let Some(pred) = predicate.to_opt_poly_trait_pred() && Some(pred.def_id()) == self.tcx.lang_items().sized_trait() @@ -2621,16 +2623,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { ObligationCauseCode::TupleElem => { err.note("only the last element of a tuple may have a dynamically sized type"); } - ObligationCauseCode::ReferenceOutlivesReferent(ref_ty) => { - err.note(format!( - "required so that reference `{ref_ty}` does not outlive its referent" - )); - } - ObligationCauseCode::ObjectTypeBound(object_ty, region) => { - err.note(format!( - "required so that the lifetime bound of `{region}` for `{object_ty}` is satisfied", - )); - } ObligationCauseCode::ItemObligation(_) | ObligationCauseCode::ExprItemObligation(..) => { // We hold the `DefId` of the item introducing the obligation, but displaying it From 3e769c55b885b763bbad4e2341ac78d08d81c1ec Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 23 Nov 2023 06:40:40 +0000 Subject: [PATCH 75/93] Remove some more unused codepaths in (region) error reporting --- compiler/rustc_infer/src/infer/error_reporting/mod.rs | 6 ------ compiler/rustc_middle/src/traits/mod.rs | 3 ++- 2 files changed, 2 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_infer/src/infer/error_reporting/mod.rs b/compiler/rustc_infer/src/infer/error_reporting/mod.rs index a2aa99e78e1e..bf9edb5b83d6 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/mod.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/mod.rs @@ -2909,9 +2909,6 @@ impl<'tcx> ObligationCauseExt<'tcx> for ObligationCause<'tcx> { CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => { "const is compatible with trait" } - ExprAssignable => "expression is assignable", - IfExpression { .. } => "`if` and `else` have incompatible types", - IfExpressionWithNoElse => "`if` missing an `else` returns `()`", MainFunctionType => "`main` function has the correct type", StartFunctionType => "`#[start]` function has the correct type", LangFunctionType(_) => "lang item function has the correct type", @@ -2932,9 +2929,6 @@ impl IntoDiagnosticArg for ObligationCauseAsDiagArg<'_> { CompareImplItemObligation { kind: ty::AssocKind::Fn, .. } => "method_compat", CompareImplItemObligation { kind: ty::AssocKind::Type, .. } => "type_compat", CompareImplItemObligation { kind: ty::AssocKind::Const, .. } => "const_compat", - ExprAssignable => "expr_assignable", - IfExpression { .. } => "if_else_different", - IfExpressionWithNoElse => "no_else", MainFunctionType => "fn_main_correct_type", StartFunctionType => "fn_start_correct_type", LangFunctionType(_) => "fn_lang_correct_type", diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index bda229c12631..6cc4803c910c 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -340,7 +340,8 @@ pub enum ObligationCauseCode<'tcx> { parent_code: InternedObligationCauseCode<'tcx>, }, - /// Error derived when matching traits/impls; see ObligationCause for more details + /// Error derived when checking an impl item is compatible with + /// its corresponding trait item's definition CompareImplItemObligation { impl_item_def_id: LocalDefId, trait_item_def_id: DefId, From ca56739366e5183d68eaec1a2a9ee6429fd4002f Mon Sep 17 00:00:00 2001 From: Michael Goulet Date: Thu, 23 Nov 2023 06:47:02 +0000 Subject: [PATCH 76/93] Remove 3 more unused ObligationCauseCodes --- compiler/rustc_middle/src/traits/mod.rs | 9 --------- .../src/traits/error_reporting/suggestions.rs | 5 ----- .../src/traits/error_reporting/type_err_ctxt_ext.rs | 1 - 3 files changed, 15 deletions(-) diff --git a/compiler/rustc_middle/src/traits/mod.rs b/compiler/rustc_middle/src/traits/mod.rs index 6cc4803c910c..853eea1a6095 100644 --- a/compiler/rustc_middle/src/traits/mod.rs +++ b/compiler/rustc_middle/src/traits/mod.rs @@ -370,9 +370,6 @@ pub enum ObligationCauseCode<'tcx> { origin_expr: bool, }, - /// Constants in patterns must have `Structural` type. - ConstPatternStructural, - /// Computing common supertype in an if expression IfExpression(Box>), @@ -405,9 +402,6 @@ pub enum ObligationCauseCode<'tcx> { /// `return` with an expression ReturnValue(hir::HirId), - /// Return type of this function - ReturnType, - /// Opaque return type of this function OpaqueReturnType(Option<(Ty<'tcx>, Span)>), @@ -417,9 +411,6 @@ pub enum ObligationCauseCode<'tcx> { /// #[feature(trivial_bounds)] is not enabled TrivialBound, - /// If `X` is the concrete type of an opaque type `impl Y`, then `X` must implement `Y` - OpaqueType, - AwaitableExpr(hir::HirId), ForLoopIterator, diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index 47eaca90d1bc..f73e6f144df9 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -2592,11 +2592,9 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::MethodReceiver | ObligationCauseCode::ReturnNoExpression | ObligationCauseCode::UnifyReceiver(..) - | ObligationCauseCode::OpaqueType | ObligationCauseCode::MiscObligation | ObligationCauseCode::WellFormed(..) | ObligationCauseCode::MatchImpl(..) - | ObligationCauseCode::ReturnType | ObligationCauseCode::ReturnValue(_) | ObligationCauseCode::BlockTailExpression(..) | ObligationCauseCode::AwaitableExpr(_) @@ -2974,9 +2972,6 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { "all values live across `{what}` must have a statically known size" )); } - ObligationCauseCode::ConstPatternStructural => { - err.note("constants used for pattern-matching must derive `PartialEq` and `Eq`"); - } ObligationCauseCode::SharedStatic => { err.note("shared static variables must have a type that implements `Sync`"); } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 5c28fec39600..5718ab3b9664 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -1448,7 +1448,6 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { | ObligationCauseCode::ExprItemObligation(..) | ObligationCauseCode::ExprBindingObligation(..) | ObligationCauseCode::Coercion { .. } - | ObligationCauseCode::OpaqueType ); // constrain inference variables a bit more to nested obligations from normalize so From 4ccec4558fea4c649ef92874bb26f3e96ab8eb21 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 14 Apr 2023 01:14:26 +0100 Subject: [PATCH 77/93] Add `debug_assert_nounwind` --- library/core/src/panic.rs | 21 ++++++++++++++ library/core/src/panicking.rs | 52 ++++++++++++++++++++++------------- 2 files changed, 54 insertions(+), 19 deletions(-) diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index b7cd10b5b19e..f5d18ca0b3f7 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -139,6 +139,27 @@ pub macro unreachable_2021 { ), } +#[doc(hidden)] +#[unstable(feature = "core_panic", issue = "none")] +#[allow_internal_unstable(core_panic, const_format_args)] +#[rustc_macro_transparency = "semitransparent"] +pub macro debug_assert_nounwind { + ($cond:expr $(,)?) => { + if $crate::cfg!(debug_assertions) { + if !$cond { + $crate::panicking::panic_nounwind($crate::concat!("assertion failed: ", $crate::stringify!($cond))); + } + } + }, + ($cond:expr, $($arg:tt)+) => { + if $crate::cfg!(debug_assertions) { + if !$cond { + $crate::panicking::panic_nounwind_fmt($crate::const_format_args!($($arg)+), false); + } + } + }, +} + /// An internal trait used by std to pass data from std to `panic_unwind` and /// other panic runtimes. Not intended to be stabilized any time soon, do not /// use. diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index fa6e5fe5d17d..1c906b7d3b41 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -82,28 +82,41 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { // and unwinds anyway, we will hit the "unwinding out of nounwind function" guard, // which causes a "panic in a function that cannot unwind". #[rustc_nounwind] -pub fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { - if cfg!(feature = "panic_immediate_abort") { - super::intrinsics::abort() +#[rustc_const_unstable(feature = "core_panic", issue = "none")] +pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { + fn runtime(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { + if cfg!(feature = "panic_immediate_abort") { + super::intrinsics::abort() + } + + // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call + // that gets resolved to the `#[panic_handler]` function. + extern "Rust" { + #[lang = "panic_impl"] + fn panic_impl(pi: &PanicInfo<'_>) -> !; + } + + // PanicInfo with the `can_unwind` flag set to false forces an abort. + let pi = PanicInfo::internal_constructor( + Some(&fmt), + Location::caller(), + /* can_unwind */ false, + force_no_backtrace, + ); + + // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. + unsafe { panic_impl(&pi) } } - // NOTE This function never crosses the FFI boundary; it's a Rust-to-Rust call - // that gets resolved to the `#[panic_handler]` function. - extern "Rust" { - #[lang = "panic_impl"] - fn panic_impl(pi: &PanicInfo<'_>) -> !; + #[inline] + const fn comptime(fmt: fmt::Arguments<'_>, _force_no_backtrace: bool) -> ! { + panic_fmt(fmt); } - // PanicInfo with the `can_unwind` flag set to false forces an abort. - let pi = PanicInfo::internal_constructor( - Some(&fmt), - Location::caller(), - /* can_unwind */ false, - force_no_backtrace, - ); - - // SAFETY: `panic_impl` is defined in safe Rust code and thus is safe to call. - unsafe { panic_impl(&pi) } + // SAFETY: const panic does not care about unwinding + unsafe { + super::intrinsics::const_eval_select((fmt, force_no_backtrace), comptime, runtime); + } } // Next we define a bunch of higher-level wrappers that all bottom out in the two core functions @@ -132,7 +145,8 @@ pub const fn panic(expr: &'static str) -> ! { #[cfg_attr(feature = "panic_immediate_abort", inline)] #[lang = "panic_nounwind"] // needed by codegen for non-unwinding panics #[rustc_nounwind] -pub fn panic_nounwind(expr: &'static str) -> ! { +#[rustc_const_unstable(feature = "core_panic", issue = "none")] +pub const fn panic_nounwind(expr: &'static str) -> ! { panic_nounwind_fmt(fmt::Arguments::new_const(&[expr]), /* force_no_backtrace */ false); } From 97c1502066349973943c0b3bb3d5810ef999856e Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 14 Apr 2023 01:22:14 +0100 Subject: [PATCH 78/93] Convert many `assert_unsafe_precondition` to `debug_assert_nounwind` --- library/core/src/hint.rs | 9 ++-- library/core/src/num/nonzero.rs | 8 +-- library/core/src/ops/index_range.rs | 13 ++--- library/core/src/ptr/alignment.rs | 12 ++--- library/core/src/slice/index.rs | 75 +++++++++++------------------ library/core/src/slice/mod.rs | 67 ++++++++++++-------------- library/core/src/str/traits.rs | 46 ++++++++---------- 7 files changed, 98 insertions(+), 132 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index ff177c70d39c..8e23d6bea3be 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -98,12 +98,13 @@ use crate::intrinsics; #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unreachable_unchecked() -> ! { + crate::panic::debug_assert_nounwind!( + false, + "hint::unreachable_unchecked must never be reached" + ); // SAFETY: the safety contract for `intrinsics::unreachable` must // be upheld by the caller. - unsafe { - intrinsics::assert_unsafe_precondition!("hint::unreachable_unchecked must never be reached", () => false); - intrinsics::unreachable() - } + unsafe { intrinsics::unreachable() } } /// Emits a machine instruction to signal the processor that it is running in diff --git a/library/core/src/num/nonzero.rs b/library/core/src/num/nonzero.rs index 7f8d673c179a..cc94ee280c68 100644 --- a/library/core/src/num/nonzero.rs +++ b/library/core/src/num/nonzero.rs @@ -75,12 +75,12 @@ macro_rules! nonzero_integers { #[must_use] #[inline] pub const unsafe fn new_unchecked(n: $Int) -> Self { + crate::panic::debug_assert_nounwind!( + n != 0, + concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument") + ); // SAFETY: this is guaranteed to be safe by the caller. unsafe { - core::intrinsics::assert_unsafe_precondition!( - concat!(stringify!($Ty), "::new_unchecked requires a non-zero argument"), - (n: $Int) => n != 0 - ); Self(n) } } diff --git a/library/core/src/ops/index_range.rs b/library/core/src/ops/index_range.rs index 265022a394e8..743799c4b3ed 100644 --- a/library/core/src/ops/index_range.rs +++ b/library/core/src/ops/index_range.rs @@ -1,4 +1,4 @@ -use crate::intrinsics::{assert_unsafe_precondition, unchecked_add, unchecked_sub}; +use crate::intrinsics::{unchecked_add, unchecked_sub}; use crate::iter::{FusedIterator, TrustedLen}; use crate::num::NonZeroUsize; @@ -19,13 +19,10 @@ impl IndexRange { /// - `start <= end` #[inline] pub const unsafe fn new_unchecked(start: usize, end: usize) -> Self { - // SAFETY: comparisons on usize are pure - unsafe { - assert_unsafe_precondition!( - "IndexRange::new_unchecked requires `start <= end`", - (start: usize, end: usize) => start <= end - ) - }; + crate::panic::debug_assert_nounwind!( + start <= end, + "IndexRange::new_unchecked requires `start <= end`" + ); IndexRange { start, end } } diff --git a/library/core/src/ptr/alignment.rs b/library/core/src/ptr/alignment.rs index e578d2257f6e..ce176e6fc18f 100644 --- a/library/core/src/ptr/alignment.rs +++ b/library/core/src/ptr/alignment.rs @@ -1,5 +1,4 @@ use crate::convert::{TryFrom, TryInto}; -use crate::intrinsics::assert_unsafe_precondition; use crate::num::NonZeroUsize; use crate::{cmp, fmt, hash, mem, num}; @@ -77,13 +76,10 @@ impl Alignment { #[rustc_const_unstable(feature = "ptr_alignment_type", issue = "102070")] #[inline] pub const unsafe fn new_unchecked(align: usize) -> Self { - // SAFETY: Precondition passed to the caller. - unsafe { - assert_unsafe_precondition!( - "Alignment::new_unchecked requires a power of two", - (align: usize) => align.is_power_of_two() - ) - }; + crate::panic::debug_assert_nounwind!( + align.is_power_of_two(), + "Alignment::new_unchecked requires a power of two" + ); // SAFETY: By precondition, this must be a power of two, and // our variants encompass all possible powers of two. diff --git a/library/core/src/slice/index.rs b/library/core/src/slice/index.rs index 1da3a87e117a..27afd3b80172 100644 --- a/library/core/src/slice/index.rs +++ b/library/core/src/slice/index.rs @@ -1,9 +1,9 @@ //! Indexing implementations for `[T]`. -use crate::intrinsics::assert_unsafe_precondition; use crate::intrinsics::const_eval_select; use crate::intrinsics::unchecked_sub; use crate::ops; +use crate::panic::debug_assert_nounwind; use crate::ptr; #[stable(feature = "rust1", since = "1.0.0")] @@ -225,31 +225,25 @@ unsafe impl SliceIndex<[T]> for usize { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const T { - let this = self; + debug_assert_nounwind!( + self < slice.len(), + "slice::get_unchecked requires that the index is within the slice", + ); // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. - unsafe { - assert_unsafe_precondition!( - "slice::get_unchecked requires that the index is within the slice", - [T](this: usize, slice: *const [T]) => this < slice.len() - ); - slice.as_ptr().add(self) - } + unsafe { slice.as_ptr().add(self) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut T { - let this = self; + debug_assert_nounwind!( + self < slice.len(), + "slice::get_unchecked_mut requires that the index is within the slice", + ); // SAFETY: see comments for `get_unchecked` above. - unsafe { - assert_unsafe_precondition!( - "slice::get_unchecked_mut requires that the index is within the slice", - [T](this: usize, slice: *mut [T]) => this < slice.len() - ); - slice.as_mut_ptr().add(self) - } + unsafe { slice.as_mut_ptr().add(self) } } #[inline] @@ -293,32 +287,25 @@ unsafe impl SliceIndex<[T]> for ops::IndexRange { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - let end = self.end(); + debug_assert_nounwind!( + self.end() <= slice.len(), + "slice::get_unchecked requires that the index is within the slice" + ); // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe. - - unsafe { - assert_unsafe_precondition!( - "slice::get_unchecked requires that the index is within the slice", - [T](end: usize, slice: *const [T]) => end <= slice.len() - ); - ptr::slice_from_raw_parts(slice.as_ptr().add(self.start()), self.len()) - } + unsafe { ptr::slice_from_raw_parts(slice.as_ptr().add(self.start()), self.len()) } } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - let end = self.end(); + debug_assert_nounwind!( + self.end() <= slice.len(), + "slice::get_unchecked_mut requires that the index is within the slice", + ); // SAFETY: see comments for `get_unchecked` above. - unsafe { - assert_unsafe_precondition!( - "slice::get_unchecked_mut requires that the index is within the slice", - [T](end: usize, slice: *mut [T]) => end <= slice.len() - ); - ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start()), self.len()) - } + unsafe { ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start()), self.len()) } } #[inline] @@ -369,17 +356,15 @@ unsafe impl SliceIndex<[T]> for ops::Range { #[inline] unsafe fn get_unchecked(self, slice: *const [T]) -> *const [T] { - let this = ops::Range { ..self }; + debug_assert_nounwind!( + self.end >= self.start && self.end <= slice.len(), + "slice::get_unchecked requires that the range is within the slice", + ); // SAFETY: the caller guarantees that `slice` is not dangling, so it // cannot be longer than `isize::MAX`. They also guarantee that // `self` is in bounds of `slice` so `self` cannot overflow an `isize`, // so the call to `add` is safe and the length calculation cannot overflow. unsafe { - assert_unsafe_precondition!( - "slice::get_unchecked requires that the range is within the slice", - [T](this: ops::Range, slice: *const [T]) => - this.end >= this.start && this.end <= slice.len() - ); let new_len = unchecked_sub(self.end, self.start); ptr::slice_from_raw_parts(slice.as_ptr().add(self.start), new_len) } @@ -387,14 +372,12 @@ unsafe impl SliceIndex<[T]> for ops::Range { #[inline] unsafe fn get_unchecked_mut(self, slice: *mut [T]) -> *mut [T] { - let this = ops::Range { ..self }; + debug_assert_nounwind!( + self.end >= self.start && self.end <= slice.len(), + "slice::get_unchecked_mut requires that the range is within the slice", + ); // SAFETY: see comments for `get_unchecked` above. unsafe { - assert_unsafe_precondition!( - "slice::get_unchecked_mut requires that the range is within the slice", - [T](this: ops::Range, slice: *mut [T]) => - this.end >= this.start && this.end <= slice.len() - ); let new_len = unchecked_sub(self.end, self.start); ptr::slice_from_raw_parts_mut(slice.as_mut_ptr().add(self.start), new_len) } diff --git a/library/core/src/slice/mod.rs b/library/core/src/slice/mod.rs index 998ece3afa95..65aae8499f3b 100644 --- a/library/core/src/slice/mod.rs +++ b/library/core/src/slice/mod.rs @@ -8,13 +8,14 @@ use crate::cmp::Ordering::{self, Equal, Greater, Less}; use crate::fmt; -use crate::intrinsics::{assert_unsafe_precondition, exact_div}; +use crate::intrinsics::exact_div; use crate::marker::Copy; use crate::mem::{self, SizedTypeProperties}; use crate::num::NonZeroUsize; use crate::ops::{Bound, FnMut, OneSidedRange, Range, RangeBounds}; use crate::option::Option; use crate::option::Option::{None, Some}; +use crate::panic::debug_assert_nounwind; use crate::ptr; use crate::result::Result; use crate::result::Result::{Err, Ok}; @@ -929,14 +930,14 @@ impl [T] { #[unstable(feature = "slice_swap_unchecked", issue = "88539")] #[rustc_const_unstable(feature = "const_swap", issue = "83163")] pub const unsafe fn swap_unchecked(&mut self, a: usize, b: usize) { - let this = self; - let ptr = this.as_mut_ptr(); + debug_assert_nounwind!( + a < self.len() && b < self.len(), + "slice::swap_unchecked requires that the indices are within the slice", + ); + + let ptr = self.as_mut_ptr(); // SAFETY: caller has to guarantee that `a < self.len()` and `b < self.len()` unsafe { - assert_unsafe_precondition!( - "slice::swap_unchecked requires that the indices are within the slice", - [T](a: usize, b: usize, this: &mut [T]) => a < this.len() && b < this.len() - ); ptr::swap(ptr.add(a), ptr.add(b)); } } @@ -1269,15 +1270,12 @@ impl [T] { #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked(&self) -> &[[T; N]] { - let this = self; + debug_assert_nounwind!( + N != 0 && self.len() % N == 0, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + ); // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length - let new_len = unsafe { - assert_unsafe_precondition!( - "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", - [T](this: &[T], N: usize) => N != 0 && this.len() % N == 0 - ); - exact_div(self.len(), N) - }; + let new_len = unsafe { exact_div(self.len(), N) }; // SAFETY: We cast a slice of `new_len * N` elements into // a slice of `new_len` many `N` elements chunks. unsafe { from_raw_parts(self.as_ptr().cast(), new_len) } @@ -1426,15 +1424,12 @@ impl [T] { #[inline] #[must_use] pub const unsafe fn as_chunks_unchecked_mut(&mut self) -> &mut [[T; N]] { - let this = &*self; + debug_assert_nounwind!( + N != 0 && self.len() % N == 0, + "slice::as_chunks_unchecked requires `N != 0` and the slice to split exactly into `N`-element chunks", + ); // SAFETY: Caller must guarantee that `N` is nonzero and exactly divides the slice length - let new_len = unsafe { - assert_unsafe_precondition!( - "slice::as_chunks_unchecked_mut requires `N != 0` and the slice to split exactly into `N`-element chunks", - [T](this: &[T], N: usize) => N != 0 && this.len() % N == 0 - ); - exact_div(this.len(), N) - }; + let new_len = unsafe { exact_div(self.len(), N) }; // SAFETY: We cast a slice of `new_len * N` elements into // a slice of `new_len` many `N` elements chunks. unsafe { from_raw_parts_mut(self.as_mut_ptr().cast(), new_len) } @@ -1967,14 +1962,13 @@ impl [T] { let len = self.len(); let ptr = self.as_ptr(); + debug_assert_nounwind!( + mid <= len, + "slice::split_at_unchecked requires the index to be within the slice", + ); + // SAFETY: Caller has to check that `0 <= mid <= self.len()` - unsafe { - assert_unsafe_precondition!( - "slice::split_at_unchecked requires the index to be within the slice", - (mid: usize, len: usize) => mid <= len - ); - (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid)) - } + unsafe { (from_raw_parts(ptr, mid), from_raw_parts(ptr.add(mid), len - mid)) } } /// Divides one mutable slice into two at an index, without doing bounds checking. @@ -2018,17 +2012,16 @@ impl [T] { let len = self.len(); let ptr = self.as_mut_ptr(); + debug_assert_nounwind!( + mid <= len, + "slice::split_at_mut_unchecked requires the index to be within the slice", + ); + // SAFETY: Caller has to check that `0 <= mid <= self.len()`. // // `[ptr; mid]` and `[mid; len]` are not overlapping, so returning a mutable reference // is fine. - unsafe { - assert_unsafe_precondition!( - "slice::split_at_mut_unchecked requires the index to be within the slice", - (mid: usize, len: usize) => mid <= len - ); - (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) - } + unsafe { (from_raw_parts_mut(ptr, mid), from_raw_parts_mut(ptr.add(mid), len - mid)) } } /// Divides one slice into an array and a remainder slice at an index. diff --git a/library/core/src/str/traits.rs b/library/core/src/str/traits.rs index 16fb1dad7230..777ad0d818b5 100644 --- a/library/core/src/str/traits.rs +++ b/library/core/src/str/traits.rs @@ -1,8 +1,8 @@ //! Trait implementations for `str`. use crate::cmp::Ordering; -use crate::intrinsics::assert_unsafe_precondition; use crate::ops; +use crate::panic::debug_assert_nounwind; use crate::ptr; use crate::slice::SliceIndex; @@ -191,39 +191,35 @@ unsafe impl SliceIndex for ops::Range { #[inline] unsafe fn get_unchecked(self, slice: *const str) -> *const Self::Output { let slice = slice as *const [u8]; + + debug_assert_nounwind!( + // We'd like to check that the bounds are on char boundaries, + // but there's not really a way to do so without reading + // behind the pointer, which has aliasing implications. + // It's also not possible to move this check up to + // `str::get_unchecked` without adding a special function + // to `SliceIndex` just for this. + self.end >= self.start && self.end <= slice.len(), + "str::get_unchecked requires that the range is within the string slice", + ); + // SAFETY: the caller guarantees that `self` is in bounds of `slice` // which satisfies all the conditions for `add`. - let ptr = unsafe { - let this = ops::Range { ..self }; - assert_unsafe_precondition!( - "str::get_unchecked requires that the range is within the string slice", - (this: ops::Range, slice: *const [u8]) => - // We'd like to check that the bounds are on char boundaries, - // but there's not really a way to do so without reading - // behind the pointer, which has aliasing implications. - // It's also not possible to move this check up to - // `str::get_unchecked` without adding a special function - // to `SliceIndex` just for this. - this.end >= this.start && this.end <= slice.len() - ); - slice.as_ptr().add(self.start) - }; + let ptr = unsafe { slice.as_ptr().add(self.start) }; let len = self.end - self.start; ptr::slice_from_raw_parts(ptr, len) as *const str } #[inline] unsafe fn get_unchecked_mut(self, slice: *mut str) -> *mut Self::Output { let slice = slice as *mut [u8]; + + debug_assert_nounwind!( + self.end >= self.start && self.end <= slice.len(), + "str::get_unchecked_mut requires that the range is within the string slice", + ); + // SAFETY: see comments for `get_unchecked`. - let ptr = unsafe { - let this = ops::Range { ..self }; - assert_unsafe_precondition!( - "str::get_unchecked_mut requires that the range is within the string slice", - (this: ops::Range, slice: *mut [u8]) => - this.end >= this.start && this.end <= slice.len() - ); - slice.as_mut_ptr().add(self.start) - }; + let ptr = unsafe { slice.as_mut_ptr().add(self.start) }; let len = self.end - self.start; ptr::slice_from_raw_parts_mut(ptr, len) as *mut str } From 81cd49ddde81eefbf5e9f51c6622874e378d5bf2 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 14 Apr 2023 15:02:13 +0100 Subject: [PATCH 79/93] Address review feedback --- library/core/src/hint.rs | 9 ++++----- library/core/src/panic.rs | 5 +++++ library/core/src/panicking.rs | 2 ++ 3 files changed, 11 insertions(+), 5 deletions(-) diff --git a/library/core/src/hint.rs b/library/core/src/hint.rs index 8e23d6bea3be..ff177c70d39c 100644 --- a/library/core/src/hint.rs +++ b/library/core/src/hint.rs @@ -98,13 +98,12 @@ use crate::intrinsics; #[rustc_const_stable(feature = "const_unreachable_unchecked", since = "1.57.0")] #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces pub const unsafe fn unreachable_unchecked() -> ! { - crate::panic::debug_assert_nounwind!( - false, - "hint::unreachable_unchecked must never be reached" - ); // SAFETY: the safety contract for `intrinsics::unreachable` must // be upheld by the caller. - unsafe { intrinsics::unreachable() } + unsafe { + intrinsics::assert_unsafe_precondition!("hint::unreachable_unchecked must never be reached", () => false); + intrinsics::unreachable() + } } /// Emits a machine instruction to signal the processor that it is running in diff --git a/library/core/src/panic.rs b/library/core/src/panic.rs index f5d18ca0b3f7..4ca5af1eaea3 100644 --- a/library/core/src/panic.rs +++ b/library/core/src/panic.rs @@ -139,6 +139,11 @@ pub macro unreachable_2021 { ), } +/// Asserts that a boolean expression is `true`, and perform a non-unwinding panic otherwise. +/// +/// This macro is similar to `debug_assert!`, but is intended to be used in code that should not +/// unwind. For example, checks in `_unchecked` functions that are intended for debugging but should +/// not compromise unwind safety. #[doc(hidden)] #[unstable(feature = "core_panic", issue = "none")] #[allow_internal_unstable(core_panic, const_format_args)] diff --git a/library/core/src/panicking.rs b/library/core/src/panicking.rs index 1c906b7d3b41..553e18c68834 100644 --- a/library/core/src/panicking.rs +++ b/library/core/src/panicking.rs @@ -84,6 +84,7 @@ pub const fn panic_fmt(fmt: fmt::Arguments<'_>) -> ! { #[rustc_nounwind] #[rustc_const_unstable(feature = "core_panic", issue = "none")] pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { + #[track_caller] fn runtime(fmt: fmt::Arguments<'_>, force_no_backtrace: bool) -> ! { if cfg!(feature = "panic_immediate_abort") { super::intrinsics::abort() @@ -109,6 +110,7 @@ pub const fn panic_nounwind_fmt(fmt: fmt::Arguments<'_>, force_no_backtrace: boo } #[inline] + #[track_caller] const fn comptime(fmt: fmt::Arguments<'_>, _force_no_backtrace: bool) -> ! { panic_fmt(fmt); } From ece0d6e79ac9c67194f40762749178f23b101a6d Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 14 Apr 2023 15:02:03 +0100 Subject: [PATCH 80/93] Fix tests --- .../consts/const-eval/raw-bytes.32bit.stderr | 110 +++++++++--------- .../consts/const-eval/raw-bytes.64bit.stderr | 110 +++++++++--------- tests/ui/consts/const-eval/raw-bytes.rs | 1 + tests/ui/consts/std/alloc.32bit.stderr | 4 +- tests/ui/consts/std/alloc.64bit.stderr | 4 +- tests/ui/consts/std/alloc.rs | 1 + tests/ui/print_type_sizes/niche-filling.rs | 1 + 7 files changed, 117 insertions(+), 114 deletions(-) diff --git a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr index 689ebf752236..c8a99b2d078f 100644 --- a/tests/ui/consts/const-eval/raw-bytes.32bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.32bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:20:1 + --> $DIR/raw-bytes.rs:21:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x00000001, but expected a valid enum tag @@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:28:1 + --> $DIR/raw-bytes.rs:29:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x00000000, but expected a valid enum tag @@ -21,7 +21,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:42:1 + --> $DIR/raw-bytes.rs:43:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant @@ -32,7 +32,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:44:1 + --> $DIR/raw-bytes.rs:45:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant @@ -43,7 +43,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:50:1 + --> $DIR/raw-bytes.rs:51:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) @@ -54,7 +54,7 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:54:1 + --> $DIR/raw-bytes.rs:55:1 | LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -65,7 +65,7 @@ LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:57:1 + --> $DIR/raw-bytes.rs:58:1 | LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -76,7 +76,7 @@ LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:59:1 + --> $DIR/raw-bytes.rs:60:1 | LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -87,7 +87,7 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:65:1 + --> $DIR/raw-bytes.rs:66:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 @@ -98,7 +98,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:71:1 + --> $DIR/raw-bytes.rs:72:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 @@ -109,7 +109,7 @@ LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:74:1 + --> $DIR/raw-bytes.rs:75:1 | LL | const NULL_FAT_PTR: NonNull = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -120,7 +120,7 @@ LL | const NULL_FAT_PTR: NonNull = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:82:1 + --> $DIR/raw-bytes.rs:83:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) @@ -131,7 +131,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:86:1 + --> $DIR/raw-bytes.rs:87:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) @@ -142,7 +142,7 @@ LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:90:1 + --> $DIR/raw-bytes.rs:91:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -153,7 +153,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:93:1 + --> $DIR/raw-bytes.rs:94:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box @@ -164,7 +164,7 @@ LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:96:1 + --> $DIR/raw-bytes.rs:97:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) @@ -175,7 +175,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:99:1 + --> $DIR/raw-bytes.rs:100:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) @@ -186,7 +186,7 @@ LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:102:1 + --> $DIR/raw-bytes.rs:103:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer @@ -197,7 +197,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:104:1 + --> $DIR/raw-bytes.rs:105:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer @@ -208,7 +208,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:106:1 + --> $DIR/raw-bytes.rs:107:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer @@ -219,7 +219,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:112:1 + --> $DIR/raw-bytes.rs:113:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar @@ -230,7 +230,7 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:137:1 + --> $DIR/raw-bytes.rs:138:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -241,7 +241,7 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:139:1 + --> $DIR/raw-bytes.rs:140:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object @@ -252,7 +252,7 @@ LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:141:1 + --> $DIR/raw-bytes.rs:142:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -263,7 +263,7 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:144:1 + --> $DIR/raw-bytes.rs:145:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected a string @@ -274,7 +274,7 @@ LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:146:1 + --> $DIR/raw-bytes.rs:147:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized memory, but expected a string @@ -285,7 +285,7 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:148:1 + --> $DIR/raw-bytes.rs:149:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a pointer, but expected a string @@ -298,7 +298,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _> = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:152:1 + --> $DIR/raw-bytes.rs:153:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -309,7 +309,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:154:1 + --> $DIR/raw-bytes.rs:155:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -320,7 +320,7 @@ LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, is } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:157:1 + --> $DIR/raw-bytes.rs:158:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) @@ -331,7 +331,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:160:1 + --> $DIR/raw-bytes.rs:161:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x03, but expected a boolean @@ -342,13 +342,13 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:160:40 + --> $DIR/raw-bytes.rs:161:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:166:1 + --> $DIR/raw-bytes.rs:167:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered 0x03, but expected a boolean @@ -359,13 +359,13 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:166:42 + --> $DIR/raw-bytes.rs:167:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:170:1 + --> $DIR/raw-bytes.rs:171:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean @@ -376,13 +376,13 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:170:42 + --> $DIR/raw-bytes.rs:171:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:175:1 + --> $DIR/raw-bytes.rs:176:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer @@ -393,7 +393,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:179:1 + --> $DIR/raw-bytes.rs:180:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer @@ -404,7 +404,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:183:1 + --> $DIR/raw-bytes.rs:184:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer @@ -415,7 +415,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:186:1 + --> $DIR/raw-bytes.rs:187:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer @@ -426,7 +426,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:190:1 + --> $DIR/raw-bytes.rs:191:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean @@ -437,7 +437,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:194:1 + --> $DIR/raw-bytes.rs:195:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer @@ -448,7 +448,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:196:1 + --> $DIR/raw-bytes.rs:197:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer @@ -459,7 +459,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:201:1 + --> $DIR/raw-bytes.rs:202:1 | LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.: encountered 0x00000000, but expected a valid enum tag @@ -470,7 +470,7 @@ LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchec } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:205:1 + --> $DIR/raw-bytes.rs:206:1 | LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.: encountered 0x00000003, but expected a valid enum tag @@ -481,7 +481,7 @@ LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unche } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:209:1 + --> $DIR/raw-bytes.rs:210:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] @@ -492,7 +492,7 @@ LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:210:1 + --> $DIR/raw-bytes.rs:211:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` @@ -503,7 +503,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:211:1 + --> $DIR/raw-bytes.rs:212:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` @@ -514,7 +514,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:215:1 + --> $DIR/raw-bytes.rs:216:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer @@ -525,7 +525,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:218:1 + --> $DIR/raw-bytes.rs:219:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer @@ -538,7 +538,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:221:1 + --> $DIR/raw-bytes.rs:222:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean @@ -549,7 +549,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:225:1 + --> $DIR/raw-bytes.rs:226:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer @@ -560,7 +560,7 @@ LL | pub static S7: &[u16] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:232:1 + --> $DIR/raw-bytes.rs:233:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer @@ -571,7 +571,7 @@ LL | pub static R4: &[u8] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:237:1 + --> $DIR/raw-bytes.rs:238:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer @@ -584,7 +584,7 @@ LL | pub static R5: &[u8] = unsafe { = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:242:1 + --> $DIR/raw-bytes.rs:243:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean diff --git a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr index 3447a8ab432c..118ab6019d6e 100644 --- a/tests/ui/consts/const-eval/raw-bytes.64bit.stderr +++ b/tests/ui/consts/const-eval/raw-bytes.64bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:20:1 + --> $DIR/raw-bytes.rs:21:1 | LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0000000000000001, but expected a valid enum tag @@ -10,7 +10,7 @@ LL | const BAD_ENUM: Enum = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:28:1 + --> $DIR/raw-bytes.rs:29:1 | LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered 0x0000000000000000, but expected a valid enum tag @@ -21,7 +21,7 @@ LL | const BAD_ENUM2: Enum2 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:42:1 + --> $DIR/raw-bytes.rs:43:1 | LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute(1u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant @@ -32,7 +32,7 @@ LL | const BAD_UNINHABITED_VARIANT1: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:44:1 + --> $DIR/raw-bytes.rs:45:1 | LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute(3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered an uninhabited enum variant @@ -43,7 +43,7 @@ LL | const BAD_UNINHABITED_VARIANT2: UninhDiscriminant = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:50:1 + --> $DIR/raw-bytes.rs:51:1 | LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::transmute(!0u32) })); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0.1: encountered 0xffffffff, but expected a valid unicode scalar value (in `0..=0x10FFFF` but not in `0xD800..=0xDFFF`) @@ -54,7 +54,7 @@ LL | const BAD_OPTION_CHAR: Option<(char, char)> = Some(('x', unsafe { mem::tran } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:54:1 + --> $DIR/raw-bytes.rs:55:1 | LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -65,7 +65,7 @@ LL | const NULL_PTR: NonNull = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:57:1 + --> $DIR/raw-bytes.rs:58:1 | LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -76,7 +76,7 @@ LL | const NULL_U8: NonZeroU8 = unsafe { mem::transmute(0u8) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:59:1 + --> $DIR/raw-bytes.rs:60:1 | LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -87,7 +87,7 @@ LL | const NULL_USIZE: NonZeroUsize = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:65:1 + --> $DIR/raw-bytes.rs:66:1 | LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 42, but expected something in the range 10..=30 @@ -98,7 +98,7 @@ LL | const BAD_RANGE1: RestrictedRange1 = unsafe { RestrictedRange1(42) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:71:1 + --> $DIR/raw-bytes.rs:72:1 | LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 20, but expected something less or equal to 10, or greater or equal to 30 @@ -109,7 +109,7 @@ LL | const BAD_RANGE2: RestrictedRange2 = unsafe { RestrictedRange2(20) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:74:1 + --> $DIR/raw-bytes.rs:75:1 | LL | const NULL_FAT_PTR: NonNull = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0, but expected something greater or equal to 1 @@ -120,7 +120,7 @@ LL | const NULL_FAT_PTR: NonNull = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:82:1 + --> $DIR/raw-bytes.rs:83:1 | LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned reference (required 2 byte alignment but found 1) @@ -131,7 +131,7 @@ LL | const UNALIGNED: &u16 = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:86:1 + --> $DIR/raw-bytes.rs:87:1 | LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered an unaligned box (required 2 byte alignment but found 1) @@ -142,7 +142,7 @@ LL | const UNALIGNED_BOX: Box = unsafe { mem::transmute(&[0u8; 4]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:90:1 + --> $DIR/raw-bytes.rs:91:1 | LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null reference @@ -153,7 +153,7 @@ LL | const NULL: &u16 = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:93:1 + --> $DIR/raw-bytes.rs:94:1 | LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a null box @@ -164,7 +164,7 @@ LL | const NULL_BOX: Box = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:96:1 + --> $DIR/raw-bytes.rs:97:1 | LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (0x539[noalloc] has no provenance) @@ -175,7 +175,7 @@ LL | const USIZE_AS_REF: &'static u8 = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:99:1 + --> $DIR/raw-bytes.rs:100:1 | LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (0x539[noalloc] has no provenance) @@ -186,7 +186,7 @@ LL | const USIZE_AS_BOX: Box = unsafe { mem::transmute(1337usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:102:1 + --> $DIR/raw-bytes.rs:103:1 | LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a function pointer @@ -197,7 +197,7 @@ LL | const NULL_FN_PTR: fn() = unsafe { mem::transmute(0usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:104:1 + --> $DIR/raw-bytes.rs:105:1 | LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered 0xd[noalloc], but expected a function pointer @@ -208,7 +208,7 @@ LL | const DANGLING_FN_PTR: fn() = unsafe { mem::transmute(13usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:106:1 + --> $DIR/raw-bytes.rs:107:1 | LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC3, but expected a function pointer @@ -219,7 +219,7 @@ LL | const DATA_FN_PTR: fn() = unsafe { mem::transmute(&13) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:112:1 + --> $DIR/raw-bytes.rs:113:1 | LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type Bar @@ -230,7 +230,7 @@ LL | const BAD_BAD_REF: &Bar = unsafe { mem::transmute(1usize) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:137:1 + --> $DIR/raw-bytes.rs:138:1 | LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -241,7 +241,7 @@ LL | const STR_TOO_LONG: &str = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:139:1 + --> $DIR/raw-bytes.rs:140:1 | LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, usize::MAX)) },); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered invalid reference metadata: slice is bigger than largest supported object @@ -252,7 +252,7 @@ LL | const NESTED_STR_MUCH_TOO_LONG: (&str,) = (unsafe { mem::transmute((&42, us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:141:1 + --> $DIR/raw-bytes.rs:142:1 | LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -263,7 +263,7 @@ LL | const MY_STR_MUCH_TOO_LONG: &MyStr = unsafe { mem::transmute((&42u8, usize: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:144:1 + --> $DIR/raw-bytes.rs:145:1 | LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .: encountered uninitialized memory, but expected a string @@ -274,7 +274,7 @@ LL | const STR_NO_INIT: &str = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit: } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:146:1 + --> $DIR/raw-bytes.rs:147:1 | LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUninit:: { uninit: () }]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered uninitialized memory, but expected a string @@ -285,7 +285,7 @@ LL | const MYSTR_NO_INIT: &MyStr = unsafe { mem::transmute::<&[_], _>(&[MaybeUni } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:148:1 + --> $DIR/raw-bytes.rs:149:1 | LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _>(&[&()]) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered a pointer, but expected a string @@ -298,7 +298,7 @@ LL | const MYSTR_NO_INIT_ISSUE83182: &MyStr = unsafe { mem::transmute::<&[_], _> = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:152:1 + --> $DIR/raw-bytes.rs:153:1 | LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling reference (going beyond the bounds of its allocation) @@ -309,7 +309,7 @@ LL | const SLICE_TOO_LONG: &[u8] = unsafe { mem::transmute((&42u8, 999usize)) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:154:1 + --> $DIR/raw-bytes.rs:155:1 | LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, isize::MAX)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered invalid reference metadata: slice is bigger than largest supported object @@ -320,7 +320,7 @@ LL | const SLICE_TOO_LONG_OVERFLOW: &[u32] = unsafe { mem::transmute((&42u32, is } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:157:1 + --> $DIR/raw-bytes.rs:158:1 | LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered a dangling box (going beyond the bounds of its allocation) @@ -331,7 +331,7 @@ LL | const SLICE_TOO_LONG_BOX: Box<[u8]> = unsafe { mem::transmute((&42u8, 999us } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:160:1 + --> $DIR/raw-bytes.rs:161:1 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x03, but expected a boolean @@ -342,13 +342,13 @@ LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:160:40 + --> $DIR/raw-bytes.rs:161:40 | LL | const SLICE_CONTENT_INVALID: &[bool] = &[unsafe { mem::transmute(3u8) }]; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:166:1 + --> $DIR/raw-bytes.rs:167:1 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..0: encountered 0x03, but expected a boolean @@ -359,13 +359,13 @@ LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3 } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:166:42 + --> $DIR/raw-bytes.rs:167:42 | LL | const MYSLICE_PREFIX_BAD: &MySliceBool = &MySlice(unsafe { mem::transmute(3u8) }, [false]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:170:1 + --> $DIR/raw-bytes.rs:171:1 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..1[0]: encountered 0x03, but expected a boolean @@ -376,13 +376,13 @@ LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::tran } note: erroneous constant encountered - --> $DIR/raw-bytes.rs:170:42 + --> $DIR/raw-bytes.rs:171:42 | LL | const MYSLICE_SUFFIX_BAD: &MySliceBool = &MySlice(true, [unsafe { mem::transmute(3u8) }]); | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:175:1 + --> $DIR/raw-bytes.rs:176:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u8))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC17, but expected a vtable pointer @@ -393,7 +393,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_1: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:179:1 + --> $DIR/raw-bytes.rs:180:1 | LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &3u64))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC19, but expected a vtable pointer @@ -404,7 +404,7 @@ LL | const TRAIT_OBJ_SHORT_VTABLE_2: W<&dyn Trait> = unsafe { mem::transmute(W(( } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:183:1 + --> $DIR/raw-bytes.rs:184:1 | LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, 4usize))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered 0x4[noalloc], but expected a vtable pointer @@ -415,7 +415,7 @@ LL | const TRAIT_OBJ_INT_VTABLE: W<&dyn Trait> = unsafe { mem::transmute(W((&92u } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:186:1 + --> $DIR/raw-bytes.rs:187:1 | LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::transmute(W((&92u8, &[&42u8; 8]))) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .0: encountered ALLOC22, but expected a vtable pointer @@ -426,7 +426,7 @@ LL | const TRAIT_OBJ_BAD_DROP_FN_NOT_FN_PTR: W<&dyn Trait> = unsafe { mem::trans } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:190:1 + --> $DIR/raw-bytes.rs:191:1 | LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, &bool>(&3u8) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at ..: encountered 0x03, but expected a boolean @@ -437,7 +437,7 @@ LL | const TRAIT_OBJ_CONTENT_INVALID: &dyn Trait = unsafe { mem::transmute::<_, } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:194:1 + --> $DIR/raw-bytes.rs:195:1 | LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute((&92u8, 0usize)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered null pointer, but expected a vtable pointer @@ -448,7 +448,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_NULL: *const dyn Trait = unsafe { mem::transmute } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:196:1 + --> $DIR/raw-bytes.rs:197:1 | LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transmute((&92u8, &3u64)) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value: encountered ALLOC27, but expected a vtable pointer @@ -459,7 +459,7 @@ LL | const RAW_TRAIT_OBJ_VTABLE_INVALID: *const dyn Trait = unsafe { mem::transm } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:201:1 + --> $DIR/raw-bytes.rs:202:1 | LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.: encountered 0x0000000000000000, but expected a valid enum tag @@ -470,7 +470,7 @@ LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchec } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:205:1 + --> $DIR/raw-bytes.rs:206:1 | LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.: encountered 0x0000000000000003, but expected a valid enum tag @@ -481,7 +481,7 @@ LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unche } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:209:1 + --> $DIR/raw-bytes.rs:210:1 | LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^^^^ constructing invalid value: encountered a reference pointing to uninhabited type [!; 1] @@ -492,7 +492,7 @@ LL | const _: &[!; 1] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:210:1 + --> $DIR/raw-bytes.rs:211:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` @@ -503,7 +503,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 1]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:211:1 + --> $DIR/raw-bytes.rs:212:1 | LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; | ^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a value of the never type `!` @@ -514,7 +514,7 @@ LL | const _: &[!] = unsafe { &*(1_usize as *const [!; 42]) }; } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:215:1 + --> $DIR/raw-bytes.rs:216:1 | LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer @@ -525,7 +525,7 @@ LL | pub static S4: &[u8] = unsafe { from_raw_parts((&D1) as *const _ as _, 1) } } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:218:1 + --> $DIR/raw-bytes.rs:219:1 | LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem::size_of::<&u32>()) }; | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer @@ -538,7 +538,7 @@ LL | pub static S5: &[u8] = unsafe { from_raw_parts((&D3) as *const _ as _, mem: = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:221:1 + --> $DIR/raw-bytes.rs:222:1 | LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) }; | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean @@ -549,7 +549,7 @@ LL | pub static S6: &[bool] = unsafe { from_raw_parts((&D0) as *const _ as _, 4) } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:225:1 + --> $DIR/raw-bytes.rs:226:1 | LL | pub static S7: &[u16] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[1]: encountered uninitialized memory, but expected an integer @@ -560,7 +560,7 @@ LL | pub static S7: &[u16] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:232:1 + --> $DIR/raw-bytes.rs:233:1 | LL | pub static R4: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered uninitialized memory, but expected an integer @@ -571,7 +571,7 @@ LL | pub static R4: &[u8] = unsafe { } error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:237:1 + --> $DIR/raw-bytes.rs:238:1 | LL | pub static R5: &[u8] = unsafe { | ^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered a pointer, but expected an integer @@ -584,7 +584,7 @@ LL | pub static R5: &[u8] = unsafe { = help: the absolute address of a pointer is not known at compile-time, so such operations are not supported error[E0080]: it is undefined behavior to use this value - --> $DIR/raw-bytes.rs:242:1 + --> $DIR/raw-bytes.rs:243:1 | LL | pub static R6: &[bool] = unsafe { | ^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .[0]: encountered 0x11, but expected a boolean diff --git a/tests/ui/consts/const-eval/raw-bytes.rs b/tests/ui/consts/const-eval/raw-bytes.rs index e005922223ad..aa4a41a7caa9 100644 --- a/tests/ui/consts/const-eval/raw-bytes.rs +++ b/tests/ui/consts/const-eval/raw-bytes.rs @@ -1,6 +1,7 @@ // stderr-per-bitwidth // ignore-endian-big // ignore-tidy-linelength +// ignore-debug debug assertions catch some UB too early // normalize-stderr-test "╾─*ALLOC[0-9]+(\+[a-z0-9]+)?─*╼" -> "╾ALLOC_ID$1╼" #![feature(never_type, rustc_attrs, ptr_metadata, slice_from_ptr_range, const_slice_from_ptr_range)] diff --git a/tests/ui/consts/std/alloc.32bit.stderr b/tests/ui/consts/std/alloc.32bit.stderr index da805de451c4..8c83df53dade 100644 --- a/tests/ui/consts/std/alloc.32bit.stderr +++ b/tests/ui/consts/std/alloc.32bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/alloc.rs:11:1 + --> $DIR/alloc.rs:12:1 | LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.: encountered 0x00000000, but expected a valid enum tag @@ -10,7 +10,7 @@ LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchec } error[E0080]: it is undefined behavior to use this value - --> $DIR/alloc.rs:15:1 + --> $DIR/alloc.rs:16:1 | LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.: encountered 0x00000003, but expected a valid enum tag diff --git a/tests/ui/consts/std/alloc.64bit.stderr b/tests/ui/consts/std/alloc.64bit.stderr index 094503e10399..addedad17047 100644 --- a/tests/ui/consts/std/alloc.64bit.stderr +++ b/tests/ui/consts/std/alloc.64bit.stderr @@ -1,5 +1,5 @@ error[E0080]: it is undefined behavior to use this value - --> $DIR/alloc.rs:11:1 + --> $DIR/alloc.rs:12:1 | LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchecked(0x1000, 0x00) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.: encountered 0x0000000000000000, but expected a valid enum tag @@ -10,7 +10,7 @@ LL | const LAYOUT_INVALID_ZERO: Layout = unsafe { Layout::from_size_align_unchec } error[E0080]: it is undefined behavior to use this value - --> $DIR/alloc.rs:15:1 + --> $DIR/alloc.rs:16:1 | LL | const LAYOUT_INVALID_THREE: Layout = unsafe { Layout::from_size_align_unchecked(9, 3) }; | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ constructing invalid value at .align.0.: encountered 0x0000000000000003, but expected a valid enum tag diff --git a/tests/ui/consts/std/alloc.rs b/tests/ui/consts/std/alloc.rs index 0a2c2f4dec80..a456a6722936 100644 --- a/tests/ui/consts/std/alloc.rs +++ b/tests/ui/consts/std/alloc.rs @@ -2,6 +2,7 @@ // Strip out raw byte dumps to make comparison platform-independent: // normalize-stderr-test "(the raw bytes of the constant) \(size: [0-9]*, align: [0-9]*\)" -> "$1 (size: $$SIZE, align: $$ALIGN)" // normalize-stderr-test "([0-9a-f][0-9a-f] |╾─*a(lloc)?[0-9]+(\+[a-z0-9]+)?─*╼ )+ *│.*" -> "HEX_DUMP" +// ignore-debug debug assertions catch some UB too early use std::alloc::Layout; // ok diff --git a/tests/ui/print_type_sizes/niche-filling.rs b/tests/ui/print_type_sizes/niche-filling.rs index 5e620f248b65..5ee5085ddc8e 100644 --- a/tests/ui/print_type_sizes/niche-filling.rs +++ b/tests/ui/print_type_sizes/niche-filling.rs @@ -1,4 +1,5 @@ // compile-flags: -Z print-type-sizes --crate-type=lib +// ignore-debug debug assertions will print more types // build-pass // ignore-pass // ^-- needed because `--pass check` does not emit the output needed. From 2c03f21d1f28d0fd7ca0475be434b1f6a303c992 Mon Sep 17 00:00:00 2001 From: Gary Guo Date: Fri, 24 Nov 2023 20:49:01 +0000 Subject: [PATCH 81/93] Bless MIR tests --- ...mut_usize.PreCodegen.after.panic-abort.mir | 45 +++++----- ...ut_usize.PreCodegen.after.panic-unwind.mir | 45 +++++----- ...mut_range.PreCodegen.after.panic-abort.mir | 83 +++++++++---------- ...ut_range.PreCodegen.after.panic-unwind.mir | 83 +++++++++---------- 4 files changed, 124 insertions(+), 132 deletions(-) diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir index 8590c9d3b837..dfdb1c9f2595 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-abort.mir @@ -20,33 +20,30 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { debug self => _2; debug slice => _5; let mut _6: *mut u32; + let mut _9: &[&str]; scope 5 { - debug this => _2; - scope 6 { - scope 7 (inlined >::get_unchecked_mut::runtime::) { - debug this => _2; - debug slice => _5; - scope 8 (inlined ptr::mut_ptr::::len) { - debug self => _5; - let mut _9: *const [u32]; - scope 9 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _9; - scope 10 { - } - } - } - } - scope 11 (inlined ptr::mut_ptr::::as_mut_ptr) { - debug self => _5; - } - scope 12 (inlined ptr::mut_ptr::::add) { - debug self => _6; - debug count => _2; - scope 13 { - } + scope 10 (inlined ptr::mut_ptr::::as_mut_ptr) { + debug self => _5; + } + scope 11 (inlined ptr::mut_ptr::::add) { + debug self => _6; + debug count => _2; + scope 12 { } } } + scope 6 (inlined ptr::mut_ptr::::len) { + debug self => _5; + let mut _10: *const [u32]; + scope 7 (inlined std::ptr::metadata::<[u32]>) { + debug ptr => _10; + scope 8 { + } + } + } + scope 9 (inlined Arguments::<'_>::new_const) { + debug pieces => _9; + } } } } @@ -73,10 +70,12 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { StorageLive(_5); _5 = &raw mut (*_1); StorageLive(_9); + StorageLive(_10); StorageLive(_6); _6 = _5 as *mut u32 (PtrToPtr); _7 = Offset(_6, _2); StorageDead(_6); + StorageDead(_10); StorageDead(_9); StorageDead(_5); _8 = &mut (*_7); diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir index 8590c9d3b837..dfdb1c9f2595 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_mut_usize.PreCodegen.after.panic-unwind.mir @@ -20,33 +20,30 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { debug self => _2; debug slice => _5; let mut _6: *mut u32; + let mut _9: &[&str]; scope 5 { - debug this => _2; - scope 6 { - scope 7 (inlined >::get_unchecked_mut::runtime::) { - debug this => _2; - debug slice => _5; - scope 8 (inlined ptr::mut_ptr::::len) { - debug self => _5; - let mut _9: *const [u32]; - scope 9 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _9; - scope 10 { - } - } - } - } - scope 11 (inlined ptr::mut_ptr::::as_mut_ptr) { - debug self => _5; - } - scope 12 (inlined ptr::mut_ptr::::add) { - debug self => _6; - debug count => _2; - scope 13 { - } + scope 10 (inlined ptr::mut_ptr::::as_mut_ptr) { + debug self => _5; + } + scope 11 (inlined ptr::mut_ptr::::add) { + debug self => _6; + debug count => _2; + scope 12 { } } } + scope 6 (inlined ptr::mut_ptr::::len) { + debug self => _5; + let mut _10: *const [u32]; + scope 7 (inlined std::ptr::metadata::<[u32]>) { + debug ptr => _10; + scope 8 { + } + } + } + scope 9 (inlined Arguments::<'_>::new_const) { + debug pieces => _9; + } } } } @@ -73,10 +70,12 @@ fn slice_get_mut_usize(_1: &mut [u32], _2: usize) -> Option<&mut u32> { StorageLive(_5); _5 = &raw mut (*_1); StorageLive(_9); + StorageLive(_10); StorageLive(_6); _6 = _5 as *mut u32 (PtrToPtr); _7 = Offset(_6, _2); StorageDead(_6); + StorageDead(_10); StorageDead(_9); StorageDead(_5); _8 = &mut (*_7); diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir index 729841ec5ea8..d7da0337dbf1 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-abort.mir @@ -19,56 +19,51 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; + let mut _14: &[&str]; scope 4 { - debug ((this: std::ops::Range).0: usize) => _3; - debug ((this: std::ops::Range).1: usize) => _4; + let _6: usize; scope 5 { - let _6: usize; - scope 6 { - debug new_len => _6; - scope 11 (inlined ptr::mut_ptr::::as_mut_ptr) { - debug self => _5; - } - scope 12 (inlined ptr::mut_ptr::::add) { - debug self => _7; - debug count => _3; - scope 13 { - } - } - scope 14 (inlined slice_from_raw_parts_mut::) { - debug data => _8; - debug len => _6; - let mut _9: *mut (); - scope 15 (inlined ptr::mut_ptr::::cast::<()>) { - debug self => _8; - } - scope 16 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { - debug data_address => _9; - debug metadata => _6; - let mut _10: *const (); - let mut _11: std::ptr::metadata::PtrComponents<[u32]>; - let mut _12: std::ptr::metadata::PtrRepr<[u32]>; - scope 17 { - } - } + debug new_len => _6; + scope 10 (inlined ptr::mut_ptr::::as_mut_ptr) { + debug self => _5; + } + scope 11 (inlined ptr::mut_ptr::::add) { + debug self => _7; + debug count => _3; + scope 12 { } } - scope 7 (inlined as SliceIndex<[T]>>::get_unchecked_mut::runtime::) { - debug ((this: std::ops::Range).0: usize) => _3; - debug ((this: std::ops::Range).1: usize) => _4; - debug slice => _5; - scope 8 (inlined ptr::mut_ptr::::len) { - debug self => _5; - let mut _14: *const [u32]; - scope 9 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _14; - scope 10 { - } + scope 13 (inlined slice_from_raw_parts_mut::) { + debug data => _8; + debug len => _6; + let mut _9: *mut (); + scope 14 (inlined ptr::mut_ptr::::cast::<()>) { + debug self => _8; + } + scope 15 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { + debug data_address => _9; + debug metadata => _6; + let mut _10: *const (); + let mut _11: std::ptr::metadata::PtrComponents<[u32]>; + let mut _12: std::ptr::metadata::PtrRepr<[u32]>; + scope 16 { } } } } } + scope 6 (inlined ptr::mut_ptr::::len) { + debug self => _5; + let mut _15: *const [u32]; + scope 7 (inlined std::ptr::metadata::<[u32]>) { + debug ptr => _15; + scope 8 { + } + } + } + scope 9 (inlined Arguments::<'_>::new_const) { + debug pieces => _14; + } } } } @@ -78,8 +73,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> _4 = move (_2.1: usize); StorageLive(_5); _5 = &raw mut (*_1); - StorageLive(_6); StorageLive(_14); + StorageLive(_6); + StorageLive(_15); _6 = SubUnchecked(_4, _3); StorageLive(_8); StorageLive(_7); @@ -100,8 +96,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageDead(_12); StorageDead(_9); StorageDead(_8); - StorageDead(_14); + StorageDead(_15); StorageDead(_6); + StorageDead(_14); StorageDead(_5); _0 = &mut (*_13); return; diff --git a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir index 729841ec5ea8..d7da0337dbf1 100644 --- a/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir +++ b/tests/mir-opt/pre-codegen/slice_index.slice_get_unchecked_mut_range.PreCodegen.after.panic-unwind.mir @@ -19,56 +19,51 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> debug slice => _5; let mut _7: *mut u32; let mut _8: *mut u32; + let mut _14: &[&str]; scope 4 { - debug ((this: std::ops::Range).0: usize) => _3; - debug ((this: std::ops::Range).1: usize) => _4; + let _6: usize; scope 5 { - let _6: usize; - scope 6 { - debug new_len => _6; - scope 11 (inlined ptr::mut_ptr::::as_mut_ptr) { - debug self => _5; - } - scope 12 (inlined ptr::mut_ptr::::add) { - debug self => _7; - debug count => _3; - scope 13 { - } - } - scope 14 (inlined slice_from_raw_parts_mut::) { - debug data => _8; - debug len => _6; - let mut _9: *mut (); - scope 15 (inlined ptr::mut_ptr::::cast::<()>) { - debug self => _8; - } - scope 16 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { - debug data_address => _9; - debug metadata => _6; - let mut _10: *const (); - let mut _11: std::ptr::metadata::PtrComponents<[u32]>; - let mut _12: std::ptr::metadata::PtrRepr<[u32]>; - scope 17 { - } - } + debug new_len => _6; + scope 10 (inlined ptr::mut_ptr::::as_mut_ptr) { + debug self => _5; + } + scope 11 (inlined ptr::mut_ptr::::add) { + debug self => _7; + debug count => _3; + scope 12 { } } - scope 7 (inlined as SliceIndex<[T]>>::get_unchecked_mut::runtime::) { - debug ((this: std::ops::Range).0: usize) => _3; - debug ((this: std::ops::Range).1: usize) => _4; - debug slice => _5; - scope 8 (inlined ptr::mut_ptr::::len) { - debug self => _5; - let mut _14: *const [u32]; - scope 9 (inlined std::ptr::metadata::<[u32]>) { - debug ptr => _14; - scope 10 { - } + scope 13 (inlined slice_from_raw_parts_mut::) { + debug data => _8; + debug len => _6; + let mut _9: *mut (); + scope 14 (inlined ptr::mut_ptr::::cast::<()>) { + debug self => _8; + } + scope 15 (inlined std::ptr::from_raw_parts_mut::<[u32]>) { + debug data_address => _9; + debug metadata => _6; + let mut _10: *const (); + let mut _11: std::ptr::metadata::PtrComponents<[u32]>; + let mut _12: std::ptr::metadata::PtrRepr<[u32]>; + scope 16 { } } } } } + scope 6 (inlined ptr::mut_ptr::::len) { + debug self => _5; + let mut _15: *const [u32]; + scope 7 (inlined std::ptr::metadata::<[u32]>) { + debug ptr => _15; + scope 8 { + } + } + } + scope 9 (inlined Arguments::<'_>::new_const) { + debug pieces => _14; + } } } } @@ -78,8 +73,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> _4 = move (_2.1: usize); StorageLive(_5); _5 = &raw mut (*_1); - StorageLive(_6); StorageLive(_14); + StorageLive(_6); + StorageLive(_15); _6 = SubUnchecked(_4, _3); StorageLive(_8); StorageLive(_7); @@ -100,8 +96,9 @@ fn slice_get_unchecked_mut_range(_1: &mut [u32], _2: std::ops::Range) -> StorageDead(_12); StorageDead(_9); StorageDead(_8); - StorageDead(_14); + StorageDead(_15); StorageDead(_6); + StorageDead(_14); StorageDead(_5); _0 = &mut (*_13); return; From 91aee2de15e52f65c070e012e7993618aed30aba Mon Sep 17 00:00:00 2001 From: r0cky Date: Sat, 25 Nov 2023 18:18:55 +0800 Subject: [PATCH 82/93] Clean dead codes --- .../rustc_borrowck/src/universal_regions.rs | 60 ------- compiler/rustc_codegen_llvm/src/type_of.rs | 17 +- .../src/mem_categorization.rs | 7 - .../rustc_infer/src/infer/nll_relate/mod.rs | 3 - .../rustc_mir_build/src/thir/pattern/mod.rs | 152 +----------------- .../src/solve/assembly/mod.rs | 2 - .../rustc_trait_selection/src/solve/mod.rs | 7 - .../src/solve/project_goals/mod.rs | 4 - .../src/solve/trait_goals.rs | 4 - library/std/src/error.rs | 8 - 10 files changed, 4 insertions(+), 260 deletions(-) diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index abeb021adc81..8a8203c901af 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -737,18 +737,6 @@ trait InferCtxtExt<'tcx> { ) -> T where T: TypeFoldable>; - - fn instantiate_bound_regions_with_nll_infer_vars_in_recursive_scope( - &self, - mir_def_id: LocalDefId, - indices: &mut UniversalRegionIndices<'tcx>, - ); - - fn instantiate_bound_regions_with_nll_infer_vars_in_item( - &self, - mir_def_id: LocalDefId, - indices: &mut UniversalRegionIndices<'tcx>, - ); } impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { @@ -799,54 +787,6 @@ impl<'cx, 'tcx> InferCtxtExt<'tcx> for BorrowckInferCtxt<'cx, 'tcx> { }); value } - - /// Finds late-bound regions that do not appear in the parameter listing and adds them to the - /// indices vector. Typically, we identify late-bound regions as we process the inputs and - /// outputs of the closure/function. However, sometimes there are late-bound regions which do - /// not appear in the fn parameters but which are nonetheless in scope. The simplest case of - /// this are unused functions, like fn foo<'a>() { } (see e.g., #51351). Despite not being used, - /// users can still reference these regions (e.g., let x: &'a u32 = &22;), so we need to create - /// entries for them and store them in the indices map. This code iterates over the complete - /// set of late-bound regions and checks for any that we have not yet seen, adding them to the - /// inputs vector. - #[instrument(skip(self, indices))] - fn instantiate_bound_regions_with_nll_infer_vars_in_recursive_scope( - &self, - mir_def_id: LocalDefId, - indices: &mut UniversalRegionIndices<'tcx>, - ) { - for_each_late_bound_region_in_recursive_scope(self.tcx, mir_def_id, |r| { - debug!(?r); - if !indices.indices.contains_key(&r) { - let region_vid = { - let name = r.get_name_or_anon(); - self.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) - }; - - debug!(?region_vid); - indices.insert_late_bound_region(r, region_vid.as_var()); - } - }); - } - - #[instrument(skip(self, indices))] - fn instantiate_bound_regions_with_nll_infer_vars_in_item( - &self, - mir_def_id: LocalDefId, - indices: &mut UniversalRegionIndices<'tcx>, - ) { - for_each_late_bound_region_in_item(self.tcx, mir_def_id, |r| { - debug!(?r); - if !indices.indices.contains_key(&r) { - let region_vid = { - let name = r.get_name_or_anon(); - self.next_nll_region_var(FR, || RegionCtxt::LateBound(name)) - }; - - indices.insert_late_bound_region(r, region_vid.as_var()); - } - }); - } } impl<'tcx> UniversalRegionIndices<'tcx> { diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index 712b6ed53330..624ce6d8813e 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{self, Ty, TypeVisitableExt}; use rustc_target::abi::HasDataLayout; use rustc_target::abi::{Abi, Align, FieldsShape}; use rustc_target::abi::{Int, Pointer, F32, F64}; -use rustc_target::abi::{PointeeInfo, Scalar, Size, TyAbiInterface, Variants}; +use rustc_target::abi::{Scalar, Size, Variants}; use smallvec::{smallvec, SmallVec}; use std::fmt::Write; @@ -184,7 +184,6 @@ pub trait LayoutLlvmExt<'tcx> { immediate: bool, ) -> &'a Type; fn llvm_field_index<'a>(&self, cx: &CodegenCx<'a, 'tcx>, index: usize) -> u64; - fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option; fn scalar_copy_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<&'a Type>; } @@ -356,20 +355,6 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { } } - // FIXME(eddyb) this having the same name as `TyAndLayout::pointee_info_at` - // (the inherent method, which is lacking this caching logic) can result in - // the uncached version being called - not wrong, but potentially inefficient. - fn pointee_info_at<'a>(&self, cx: &CodegenCx<'a, 'tcx>, offset: Size) -> Option { - if let Some(&pointee) = cx.pointee_infos.borrow().get(&(self.ty, offset)) { - return pointee; - } - - let result = Ty::ty_and_layout_pointee_info_at(*self, cx, offset); - - cx.pointee_infos.borrow_mut().insert((self.ty, offset), result); - result - } - fn scalar_copy_llvm_type<'a>(&self, cx: &CodegenCx<'a, 'tcx>) -> Option<&'a Type> { debug_assert!(self.is_sized()); diff --git a/compiler/rustc_hir_typeck/src/mem_categorization.rs b/compiler/rustc_hir_typeck/src/mem_categorization.rs index b25830675b28..94da4bfcdc49 100644 --- a/compiler/rustc_hir_typeck/src/mem_categorization.rs +++ b/compiler/rustc_hir_typeck/src/mem_categorization.rs @@ -66,25 +66,18 @@ use rustc_trait_selection::infer::InferCtxtExt; pub(crate) trait HirNode { fn hir_id(&self) -> hir::HirId; - fn span(&self) -> Span; } impl HirNode for hir::Expr<'_> { fn hir_id(&self) -> hir::HirId { self.hir_id } - fn span(&self) -> Span { - self.span - } } impl HirNode for hir::Pat<'_> { fn hir_id(&self) -> hir::HirId { self.hir_id } - fn span(&self) -> Span { - self.span - } } #[derive(Clone)] diff --git a/compiler/rustc_infer/src/infer/nll_relate/mod.rs b/compiler/rustc_infer/src/infer/nll_relate/mod.rs index c80491643913..ee6a3fd0c827 100644 --- a/compiler/rustc_infer/src/infer/nll_relate/mod.rs +++ b/compiler/rustc_infer/src/infer/nll_relate/mod.rs @@ -113,9 +113,6 @@ pub trait TypeRelatingDelegate<'tcx> { fn forbid_inference_vars() -> bool; } -#[derive(Copy, Clone)] -struct UniversallyQuantified(bool); - impl<'me, 'tcx, D> TypeRelating<'me, 'tcx, D> where D: TypeRelatingDelegate<'tcx>, diff --git a/compiler/rustc_mir_build/src/thir/pattern/mod.rs b/compiler/rustc_mir_build/src/thir/pattern/mod.rs index d80497fd45f9..8b2a96cff41d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/mod.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/mod.rs @@ -18,17 +18,14 @@ use rustc_hir::pat_util::EnumerateAndAdjustIterator; use rustc_hir::RangeEnd; use rustc_index::Idx; use rustc_middle::mir::interpret::{ErrorHandled, GlobalId, LitToConstError, LitToConstInput}; -use rustc_middle::mir::{self, BorrowKind, Const, Mutability, UserTypeProjection}; +use rustc_middle::mir::{self, BorrowKind, Const, Mutability}; use rustc_middle::thir::{ Ascription, BindingMode, FieldPat, LocalVarId, Pat, PatKind, PatRange, PatRangeBoundary, }; use rustc_middle::ty::layout::IntegerExt; -use rustc_middle::ty::{ - self, AdtDef, CanonicalUserTypeAnnotation, GenericArg, GenericArgsRef, Region, Ty, TyCtxt, - TypeVisitableExt, UserType, -}; +use rustc_middle::ty::{self, CanonicalUserTypeAnnotation, Ty, TyCtxt, TypeVisitableExt}; use rustc_span::def_id::LocalDefId; -use rustc_span::{ErrorGuaranteed, Span, Symbol}; +use rustc_span::{ErrorGuaranteed, Span}; use rustc_target::abi::{FieldIdx, Integer}; use std::cmp::Ordering; @@ -701,146 +698,3 @@ impl<'tcx> UserAnnotatedTyHelpers<'tcx> for PatCtxt<'_, 'tcx> { self.typeck_results } } - -trait PatternFoldable<'tcx>: Sized { - fn fold_with>(&self, folder: &mut F) -> Self { - self.super_fold_with(folder) - } - - fn super_fold_with>(&self, folder: &mut F) -> Self; -} - -trait PatternFolder<'tcx>: Sized { - fn fold_pattern(&mut self, pattern: &Pat<'tcx>) -> Pat<'tcx> { - pattern.super_fold_with(self) - } - - fn fold_pattern_kind(&mut self, kind: &PatKind<'tcx>) -> PatKind<'tcx> { - kind.super_fold_with(self) - } -} - -impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box { - fn super_fold_with>(&self, folder: &mut F) -> Self { - let content: T = (**self).fold_with(folder); - Box::new(content) - } -} - -impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Vec { - fn super_fold_with>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect() - } -} - -impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Box<[T]> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - self.iter().map(|t| t.fold_with(folder)).collect() - } -} - -impl<'tcx, T: PatternFoldable<'tcx>> PatternFoldable<'tcx> for Option { - fn super_fold_with>(&self, folder: &mut F) -> Self { - self.as_ref().map(|t| t.fold_with(folder)) - } -} - -macro_rules! ClonePatternFoldableImpls { - (<$lt_tcx:tt> $($ty:ty),+) => { - $( - impl<$lt_tcx> PatternFoldable<$lt_tcx> for $ty { - fn super_fold_with>(&self, _: &mut F) -> Self { - Clone::clone(self) - } - } - )+ - } -} - -ClonePatternFoldableImpls! { <'tcx> - Span, FieldIdx, Mutability, Symbol, LocalVarId, usize, - Region<'tcx>, Ty<'tcx>, BindingMode, AdtDef<'tcx>, - GenericArgsRef<'tcx>, &'tcx GenericArg<'tcx>, UserType<'tcx>, - UserTypeProjection, CanonicalUserTypeAnnotation<'tcx> -} - -impl<'tcx> PatternFoldable<'tcx> for FieldPat<'tcx> { - fn super_fold_with>(&self, folder: &mut F) -> Self { - FieldPat { field: self.field.fold_with(folder), pattern: self.pattern.fold_with(folder) } - } -} - -impl<'tcx> PatternFoldable<'tcx> for Pat<'tcx> { - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_pattern(self) - } - - fn super_fold_with>(&self, folder: &mut F) -> Self { - Pat { - ty: self.ty.fold_with(folder), - span: self.span.fold_with(folder), - kind: self.kind.fold_with(folder), - } - } -} - -impl<'tcx> PatternFoldable<'tcx> for PatKind<'tcx> { - fn fold_with>(&self, folder: &mut F) -> Self { - folder.fold_pattern_kind(self) - } - - fn super_fold_with>(&self, folder: &mut F) -> Self { - match *self { - PatKind::Wild => PatKind::Wild, - PatKind::Error(e) => PatKind::Error(e), - PatKind::AscribeUserType { - ref subpattern, - ascription: Ascription { ref annotation, variance }, - } => PatKind::AscribeUserType { - subpattern: subpattern.fold_with(folder), - ascription: Ascription { annotation: annotation.fold_with(folder), variance }, - }, - PatKind::Binding { mutability, name, mode, var, ty, ref subpattern, is_primary } => { - PatKind::Binding { - mutability: mutability.fold_with(folder), - name: name.fold_with(folder), - mode: mode.fold_with(folder), - var: var.fold_with(folder), - ty: ty.fold_with(folder), - subpattern: subpattern.fold_with(folder), - is_primary, - } - } - PatKind::Variant { adt_def, args, variant_index, ref subpatterns } => { - PatKind::Variant { - adt_def: adt_def.fold_with(folder), - args: args.fold_with(folder), - variant_index, - subpatterns: subpatterns.fold_with(folder), - } - } - PatKind::Leaf { ref subpatterns } => { - PatKind::Leaf { subpatterns: subpatterns.fold_with(folder) } - } - PatKind::Deref { ref subpattern } => { - PatKind::Deref { subpattern: subpattern.fold_with(folder) } - } - PatKind::Constant { value } => PatKind::Constant { value }, - PatKind::InlineConstant { def, subpattern: ref pattern } => { - PatKind::InlineConstant { def, subpattern: pattern.fold_with(folder) } - } - PatKind::Range(ref range) => PatKind::Range(range.clone()), - PatKind::Slice { ref prefix, ref slice, ref suffix } => PatKind::Slice { - prefix: prefix.fold_with(folder), - slice: slice.fold_with(folder), - suffix: suffix.fold_with(folder), - }, - PatKind::Array { ref prefix, ref slice, ref suffix } => PatKind::Array { - prefix: prefix.fold_with(folder), - slice: slice.fold_with(folder), - suffix: suffix.fold_with(folder), - }, - PatKind::Or { ref pats } => PatKind::Or { pats: pats.fold_with(folder) }, - } - } -} diff --git a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs index 59c979cf437f..eb30b4cd85ea 100644 --- a/compiler/rustc_trait_selection/src/solve/assembly/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/assembly/mod.rs @@ -37,8 +37,6 @@ pub(super) trait GoalKind<'tcx>: fn trait_ref(self, tcx: TyCtxt<'tcx>) -> ty::TraitRef<'tcx>; - fn polarity(self) -> ty::ImplPolarity; - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self; fn trait_def_id(self, tcx: TyCtxt<'tcx>) -> DefId; diff --git a/compiler/rustc_trait_selection/src/solve/mod.rs b/compiler/rustc_trait_selection/src/solve/mod.rs index 0cf4799f86d0..b526fa19c130 100644 --- a/compiler/rustc_trait_selection/src/solve/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/mod.rs @@ -64,8 +64,6 @@ enum GoalEvaluationKind { trait CanonicalResponseExt { fn has_no_inference_or_external_constraints(&self) -> bool; - - fn has_only_region_constraints(&self) -> bool; } impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { @@ -74,11 +72,6 @@ impl<'tcx> CanonicalResponseExt for Canonical<'tcx, Response<'tcx>> { && self.value.var_values.is_identity() && self.value.external_constraints.opaque_types.is_empty() } - - fn has_only_region_constraints(&self) -> bool { - self.value.var_values.is_identity_modulo_regions() - && self.value.external_constraints.opaque_types.is_empty() - } } impl<'a, 'tcx> EvalCtxt<'a, 'tcx> { diff --git a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs index 6c29ce492df0..37bbf32c7682 100644 --- a/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs +++ b/compiler/rustc_trait_selection/src/solve/project_goals/mod.rs @@ -101,10 +101,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for ProjectionPredicate<'tcx> { self.projection_ty.trait_ref(tcx) } - fn polarity(self) -> ty::ImplPolarity { - ty::ImplPolarity::Positive - } - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { self.with_self_ty(tcx, self_ty) } diff --git a/compiler/rustc_trait_selection/src/solve/trait_goals.rs b/compiler/rustc_trait_selection/src/solve/trait_goals.rs index a0c065dfa03b..95712da3c5e8 100644 --- a/compiler/rustc_trait_selection/src/solve/trait_goals.rs +++ b/compiler/rustc_trait_selection/src/solve/trait_goals.rs @@ -24,10 +24,6 @@ impl<'tcx> assembly::GoalKind<'tcx> for TraitPredicate<'tcx> { self.trait_ref } - fn polarity(self) -> ty::ImplPolarity { - self.polarity - } - fn with_self_ty(self, tcx: TyCtxt<'tcx>, self_ty: Ty<'tcx>) -> Self { self.with_self_ty(tcx, self_ty) } diff --git a/library/std/src/error.rs b/library/std/src/error.rs index 375ff2d24504..b240e4e2c45b 100644 --- a/library/std/src/error.rs +++ b/library/std/src/error.rs @@ -12,14 +12,6 @@ pub use core::error::Error; #[unstable(feature = "error_generic_member_access", issue = "99301")] pub use core::error::{request_ref, request_value, Request}; -mod private { - // This is a hack to prevent `type_id` from being overridden by `Error` - // implementations, since that can enable unsound downcasting. - #[unstable(feature = "error_type_id", issue = "60784")] - #[derive(Debug)] - pub struct Internal; -} - /// An error reporter that prints an error and its sources. /// /// Report also exposes configuration options for formatting the error sources, either entirely on a From c697927f443043fb9715b9b239fa1d2440c0e53c Mon Sep 17 00:00:00 2001 From: Vadim Petrochenkov Date: Fri, 24 Nov 2023 19:28:19 +0300 Subject: [PATCH 83/93] rustc: `hir().local_def_id_to_hir_id()` -> `tcx.local_def_id_to_hir_id()` cleanup --- .../src/diagnostics/conflict_errors.rs | 4 ++-- compiler/rustc_borrowck/src/diagnostics/mod.rs | 2 +- .../src/diagnostics/mutability_errors.rs | 2 +- .../src/diagnostics/region_errors.rs | 4 ++-- .../rustc_borrowck/src/diagnostics/region_name.rs | 2 +- compiler/rustc_borrowck/src/lib.rs | 2 +- compiler/rustc_borrowck/src/universal_regions.rs | 2 +- compiler/rustc_codegen_ssa/src/codegen_attrs.rs | 4 ++-- .../rustc_const_eval/src/interpret/eval_context.rs | 2 +- .../src/transform/check_consts/mod.rs | 2 +- .../src/transform/check_consts/ops.rs | 2 +- compiler/rustc_hir_analysis/src/astconv/errors.rs | 2 +- compiler/rustc_hir_analysis/src/astconv/mod.rs | 4 ++-- compiler/rustc_hir_analysis/src/check/check.rs | 10 ++++------ .../src/check/compare_impl_item.rs | 6 +++--- compiler/rustc_hir_analysis/src/check/entry.rs | 8 ++++---- compiler/rustc_hir_analysis/src/check/mod.rs | 2 +- .../rustc_hir_analysis/src/coherence/orphan.rs | 2 +- compiler/rustc_hir_analysis/src/collect.rs | 10 +++++----- .../rustc_hir_analysis/src/collect/generics_of.rs | 2 +- .../rustc_hir_analysis/src/collect/item_bounds.rs | 2 +- .../src/collect/predicates_of.rs | 14 +++++++------- .../src/collect/resolve_bound_vars.rs | 4 ++-- compiler/rustc_hir_analysis/src/collect/type_of.rs | 6 +++--- .../src/collect/type_of/opaque.rs | 4 ++-- compiler/rustc_hir_analysis/src/hir_wf_check.rs | 2 +- compiler/rustc_hir_analysis/src/outlives/mod.rs | 2 +- compiler/rustc_hir_typeck/src/check.rs | 2 +- compiler/rustc_hir_typeck/src/closure.rs | 2 +- compiler/rustc_hir_typeck/src/demand.rs | 2 +- compiler/rustc_hir_typeck/src/expr.rs | 8 ++++---- compiler/rustc_hir_typeck/src/expr_use_visitor.rs | 2 +- .../rustc_hir_typeck/src/fn_ctxt/suggestions.rs | 2 +- compiler/rustc_hir_typeck/src/inherited.rs | 2 +- compiler/rustc_hir_typeck/src/lib.rs | 4 ++-- compiler/rustc_hir_typeck/src/method/probe.rs | 4 ++-- compiler/rustc_hir_typeck/src/method/suggest.rs | 4 ++-- compiler/rustc_hir_typeck/src/upvar.rs | 4 ++-- compiler/rustc_hir_typeck/src/writeback.rs | 8 ++++---- compiler/rustc_incremental/src/assert_dep_graph.rs | 2 +- compiler/rustc_infer/src/errors/mod.rs | 2 +- .../nice_region_error/find_anon_type.rs | 2 +- .../nice_region_error/trait_impl_difference.rs | 2 +- .../error_reporting/nice_region_error/util.rs | 2 +- .../src/infer/error_reporting/note_and_explain.rs | 2 +- compiler/rustc_infer/src/infer/opaque_types.rs | 4 ++-- compiler/rustc_lint/src/builtin.rs | 2 +- compiler/rustc_lint/src/late.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 2 +- compiler/rustc_middle/src/hir/map/mod.rs | 11 +++-------- compiler/rustc_middle/src/hir/mod.rs | 8 ++++---- compiler/rustc_middle/src/mir/interpret/queries.rs | 2 +- .../src/traits/specialization_graph.rs | 2 +- compiler/rustc_middle/src/ty/closure.rs | 2 +- compiler/rustc_middle/src/ty/context.rs | 4 ++-- compiler/rustc_middle/src/ty/mod.rs | 6 +++--- compiler/rustc_middle/src/values.rs | 2 +- compiler/rustc_mir_build/src/build/mod.rs | 6 +++--- compiler/rustc_mir_build/src/check_unsafety.rs | 4 ++-- compiler/rustc_mir_build/src/lints.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/expr.rs | 2 +- compiler/rustc_mir_build/src/thir/cx/mod.rs | 4 ++-- .../src/thir/pattern/check_match.rs | 2 +- compiler/rustc_mir_transform/src/check_unsafety.rs | 4 ++-- compiler/rustc_passes/src/check_const.rs | 2 +- compiler/rustc_passes/src/dead.rs | 12 ++++++------ compiler/rustc_passes/src/lang_items.rs | 2 +- compiler/rustc_passes/src/naked_functions.rs | 2 +- compiler/rustc_passes/src/reachable.rs | 4 +--- compiler/rustc_passes/src/stability.rs | 4 ++-- compiler/rustc_privacy/src/lib.rs | 12 ++++++------ .../src/traits/error_reporting/on_unimplemented.rs | 10 +++++----- .../src/traits/error_reporting/suggestions.rs | 6 +++--- .../traits/error_reporting/type_err_ctxt_ext.rs | 2 +- .../src/traits/specialize/mod.rs | 2 +- compiler/rustc_ty_utils/src/assoc.rs | 2 +- compiler/rustc_ty_utils/src/opaque_types.rs | 4 ++-- src/librustdoc/clean/inline.rs | 2 +- src/librustdoc/clean/types.rs | 2 +- src/librustdoc/core.rs | 4 ++-- src/librustdoc/doctest.rs | 2 +- src/librustdoc/html/markdown.rs | 4 ++-- src/librustdoc/passes/check_doc_test_visibility.rs | 2 +- .../passes/lint/check_code_block_syntax.rs | 2 +- src/librustdoc/visit_ast.rs | 5 ++--- src/tools/clippy/clippy_lints/src/derive.rs | 6 +++--- .../clippy/clippy_lints/src/error_impl_error.rs | 2 +- src/tools/clippy/clippy_lints/src/escape.rs | 2 +- .../clippy/clippy_lints/src/excessive_bools.rs | 2 +- src/tools/clippy/clippy_lints/src/functions/mod.rs | 2 +- .../clippy/clippy_lints/src/future_not_send.rs | 2 +- src/tools/clippy/clippy_lints/src/inherent_impl.rs | 4 ++-- src/tools/clippy/clippy_lints/src/len_zero.rs | 2 +- .../clippy_lints/src/manual_non_exhaustive.rs | 2 +- .../src/methods/filter_map_bool_then.rs | 2 +- .../clippy_lints/src/missing_const_for_fn.rs | 2 +- .../clippy_lints/src/needless_pass_by_ref_mut.rs | 4 ++-- .../clippy_lints/src/needless_pass_by_value.rs | 2 +- .../clippy/clippy_lints/src/new_without_default.rs | 4 ++-- .../clippy_lints/src/non_send_fields_in_send_ty.rs | 2 +- .../clippy/clippy_lints/src/panic_in_result_fn.rs | 2 +- .../clippy_lints/src/pass_by_ref_or_value.rs | 2 +- .../clippy_lints/src/return_self_not_must_use.rs | 2 +- .../clippy_lints/src/self_named_constructors.rs | 2 +- src/tools/clippy/clippy_lints/src/types/mod.rs | 2 +- .../clippy_lints/src/undocumented_unsafe_blocks.rs | 4 ++-- .../clippy/clippy_lints/src/unnecessary_wraps.rs | 2 +- src/tools/clippy/clippy_utils/src/lib.rs | 6 +++--- src/tools/clippy/clippy_utils/src/ty.rs | 2 +- src/tools/miri/src/bin/miri.rs | 2 +- 110 files changed, 189 insertions(+), 199 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 6d4c46553c9a..7eb0d5537471 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -413,7 +413,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { (None, &[][..], 0) }; if let Some(def_id) = def_id - && let Some(node) = hir.find(hir.local_def_id_to_hir_id(def_id)) + && let Some(node) = hir.find(self.infcx.tcx.local_def_id_to_hir_id(def_id)) && let Some(fn_sig) = node.fn_sig() && let Some(ident) = node.ident() && let Some(pos) = args.iter().position(|arg| arg.hir_id == expr.hir_id) @@ -3243,7 +3243,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { ) -> Option> { debug!("annotate_fn_sig: did={:?} sig={:?}", did, sig); let is_closure = self.infcx.tcx.is_closure(did.to_def_id()); - let fn_hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(did); + let fn_hir_id = self.infcx.tcx.local_def_id_to_hir_id(did); let fn_decl = self.infcx.tcx.hir().fn_decl_by_hir_id(fn_hir_id)?; // We need to work out which arguments to highlight. We do this by looking diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index fca3d6959355..1a3848eee78d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -958,7 +958,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { "closure_span: def_id={:?} target_place={:?} places={:?}", def_id, target_place, places ); - let hir_id = self.infcx.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = self.infcx.tcx.local_def_id_to_hir_id(def_id); let expr = &self.infcx.tcx.hir().expect_expr(hir_id).kind; debug!("closure_span: hir_id={:?} expr={:?}", hir_id, expr); if let hir::ExprKind::Closure(&hir::Closure { body, fn_decl_span, .. }) = expr { diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index dde46eef6a0d..a11710e0bb06 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -661,7 +661,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { } let hir_map = self.infcx.tcx.hir(); let my_def = self.body.source.def_id(); - let my_hir = hir_map.local_def_id_to_hir_id(my_def.as_local().unwrap()); + let my_hir = self.infcx.tcx.local_def_id_to_hir_id(my_def.as_local().unwrap()); let Some(td) = self.infcx.tcx.impl_of_method(my_def).and_then(|x| self.infcx.tcx.trait_id_of_impl(x)) else { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 759d8ef30b1e..1de1c181ef41 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -215,7 +215,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { .map(|placeholder| { if let Some(id) = placeholder.bound.kind.get_id() && let Some(placeholder_id) = id.as_local() - && let gat_hir_id = hir.local_def_id_to_hir_id(placeholder_id) + && let gat_hir_id = self.infcx.tcx.local_def_id_to_hir_id(placeholder_id) && let Some(generics_impl) = hir.get_parent(gat_hir_id).generics() { Some((gat_hir_id, generics_impl)) @@ -236,7 +236,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; if bound_generic_params .iter() - .rfind(|bgp| hir.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id) + .rfind(|bgp| self.infcx.tcx.local_def_id_to_hir_id(bgp.def_id) == *gat_hir_id) .is_some() { for bound in *bounds { diff --git a/compiler/rustc_borrowck/src/diagnostics/region_name.rs b/compiler/rustc_borrowck/src/diagnostics/region_name.rs index 5cec966e1b53..730b65898bc3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_name.rs @@ -199,7 +199,7 @@ impl<'tcx> MirBorrowckCtxt<'_, 'tcx> { } pub(crate) fn mir_hir_id(&self) -> hir::HirId { - self.infcx.tcx.hir().local_def_id_to_hir_id(self.mir_def_id()) + self.infcx.tcx.local_def_id_to_hir_id(self.mir_def_id()) } /// Generate a synthetic region named `'N`, where `N` is the next value of the counter. Then, diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 822519f2f081..48e75adee4c6 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -134,7 +134,7 @@ fn mir_borrowck(tcx: TyCtxt<'_>, def: LocalDefId) -> &BorrowCheckResult<'_> { return tcx.arena.alloc(result); } - let hir_owner = tcx.hir().local_def_id_to_hir_id(def).owner; + let hir_owner = tcx.local_def_id_to_hir_id(def).owner; let infcx = tcx.infer_ctxt().with_opaque_type_inference(DefiningAnchor::Bind(hir_owner.def_id)).build(); diff --git a/compiler/rustc_borrowck/src/universal_regions.rs b/compiler/rustc_borrowck/src/universal_regions.rs index abeb021adc81..c3c2f5363623 100644 --- a/compiler/rustc_borrowck/src/universal_regions.rs +++ b/compiler/rustc_borrowck/src/universal_regions.rs @@ -928,7 +928,7 @@ fn for_each_late_bound_region_in_item<'tcx>( return; } - for bound_var in tcx.late_bound_vars(tcx.hir().local_def_id_to_hir_id(mir_def_id)) { + for bound_var in tcx.late_bound_vars(tcx.local_def_id_to_hir_id(mir_def_id)) { let ty::BoundVariableKind::Region(bound_region) = bound_var else { continue; }; diff --git a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs index f6ae4db62f94..e2b36fbd65b0 100644 --- a/compiler/rustc_codegen_ssa/src/codegen_attrs.rs +++ b/compiler/rustc_codegen_ssa/src/codegen_attrs.rs @@ -57,7 +57,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { ); } - let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(did)); + let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(did)); let mut codegen_fn_attrs = CodegenFnAttrs::new(); if tcx.should_inherit_track_caller(did) { codegen_fn_attrs.flags |= CodegenFnAttrFlags::TRACK_CALLER; @@ -572,7 +572,7 @@ fn codegen_fn_attrs(tcx: TyCtxt<'_>, did: LocalDefId) -> CodegenFnAttrs { if !codegen_fn_attrs.no_sanitize.is_empty() { if codegen_fn_attrs.inline == InlineAttr::Always { if let (Some(no_sanitize_span), Some(inline_span)) = (no_sanitize_span, inline_span) { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); + let hir_id = tcx.local_def_id_to_hir_id(did); tcx.struct_span_lint_hir( lint::builtin::INLINE_NO_SANITIZE, hir_id, diff --git a/compiler/rustc_const_eval/src/interpret/eval_context.rs b/compiler/rustc_const_eval/src/interpret/eval_context.rs index 07cab5e3400e..3bdfc1db913a 100644 --- a/compiler/rustc_const_eval/src/interpret/eval_context.rs +++ b/compiler/rustc_const_eval/src/interpret/eval_context.rs @@ -456,7 +456,7 @@ impl<'mir, 'tcx: 'mir, M: Machine<'mir, 'tcx>> InterpCx<'mir, 'tcx, M> { self.stack() .iter() .find_map(|frame| frame.body.source.def_id().as_local()) - .map_or(CRATE_HIR_ID, |def_id| self.tcx.hir().local_def_id_to_hir_id(def_id)) + .map_or(CRATE_HIR_ID, |def_id| self.tcx.local_def_id_to_hir_id(def_id)) } /// Turn the given error into a human-readable string. Expects the string to be printed, so if diff --git a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs index 095e119d38c5..4c2492d1867e 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/mod.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/mod.rs @@ -82,7 +82,7 @@ pub fn rustc_allow_const_fn_unstable( def_id: LocalDefId, feature_gate: Symbol, ) -> bool { - let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id)); + let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id)); attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate) } diff --git a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs index ca63eb135bda..5bf9911269cb 100644 --- a/compiler/rustc_const_eval/src/transform/check_consts/ops.rs +++ b/compiler/rustc_const_eval/src/transform/check_consts/ops.rs @@ -119,7 +119,7 @@ impl<'tcx> NonConstOp<'tcx> for FnCallNonConst<'tcx> { match self_ty.kind() { Param(param_ty) => { debug!(?param_ty); - let caller_hir_id = tcx.hir().local_def_id_to_hir_id(caller); + let caller_hir_id = tcx.local_def_id_to_hir_id(caller); if let Some(generics) = tcx.hir().get(caller_hir_id).generics() { let constraint = with_no_trimmed_paths!(format!( "~const {}", diff --git a/compiler/rustc_hir_analysis/src/astconv/errors.rs b/compiler/rustc_hir_analysis/src/astconv/errors.rs index 5a70a842f0d9..b53ffb98bf4f 100644 --- a/compiler/rustc_hir_analysis/src/astconv/errors.rs +++ b/compiler/rustc_hir_analysis/src/astconv/errors.rs @@ -201,7 +201,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { ); let hir = self.tcx().hir(); if let Some(def_id) = ty_param_def_id - && let parent = hir.get_parent_item(hir.local_def_id_to_hir_id(def_id)) + && let parent = hir.get_parent_item(self.tcx().local_def_id_to_hir_id(def_id)) && let Some(generics) = hir.get_generics(parent.def_id) { if generics.bounds_for_param(def_id).flat_map(|pred| pred.bounds.iter()).any( diff --git a/compiler/rustc_hir_analysis/src/astconv/mod.rs b/compiler/rustc_hir_analysis/src/astconv/mod.rs index 77fc9884d616..94b182e09f68 100644 --- a/compiler/rustc_hir_analysis/src/astconv/mod.rs +++ b/compiler/rustc_hir_analysis/src/astconv/mod.rs @@ -239,7 +239,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { def: Option<&ty::GenericParamDef>, ) -> ty::Region<'tcx> { let tcx = self.tcx(); - let lifetime_name = |def_id| tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id)); + let lifetime_name = |def_id| tcx.hir().name(tcx.local_def_id_to_hir_id(def_id)); match tcx.named_bound_var(lifetime.hir_id) { Some(rbv::ResolvedArg::StaticLifetime) => tcx.lifetimes.re_static, @@ -1872,7 +1872,7 @@ impl<'o, 'tcx> dyn AstConv<'tcx> + 'o { let parent_def_id = def_id .as_local() - .map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) + .map(|def_id| tcx.local_def_id_to_hir_id(def_id)) .map(|hir_id| tcx.hir().get_parent_item(hir_id).to_def_id()); debug!("qpath_to_ty: parent_def_id={:?}", parent_def_id); diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 00f636862beb..b279564ed455 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -188,7 +188,7 @@ fn check_static_inhabited(tcx: TyCtxt<'_>, def_id: LocalDefId) { if layout.abi.is_uninhabited() { tcx.struct_span_lint_hir( UNINHABITED_STATIC, - tcx.hir().local_def_id_to_hir_id(def_id), + tcx.local_def_id_to_hir_id(def_id), span, "static of uninhabited type", |lint| { @@ -753,8 +753,7 @@ fn check_impl_items_against_trait<'tcx>( leaf_def.as_ref().is_some_and(|node_item| !node_item.defining_node.is_from_trait()); if !is_implemented_here { - let full_impl_span = - tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(impl_id)); + let full_impl_span = tcx.hir().span_with_body(tcx.local_def_id_to_hir_id(impl_id)); match tcx.eval_default_body_stability(trait_item_id, full_impl_span) { EvalResult::Deny { feature, reason, issue, .. } => default_body_is_unstable( tcx, @@ -811,8 +810,7 @@ fn check_impl_items_against_trait<'tcx>( } if !missing_items.is_empty() { - let full_impl_span = - tcx.hir().span_with_body(tcx.hir().local_def_id_to_hir_id(impl_id)); + let full_impl_span = tcx.hir().span_with_body(tcx.local_def_id_to_hir_id(impl_id)); missing_items_err(tcx, impl_id, &missing_items, full_impl_span); } @@ -1083,7 +1081,7 @@ pub(super) fn check_transparent<'tcx>(tcx: TyCtxt<'tcx>, adt: ty::AdtDef<'tcx>) if non_trivial_count > 0 || prev_non_exhaustive_1zst { tcx.struct_span_lint_hir( REPR_TRANSPARENT_EXTERNAL_PRIVATE_FIELDS, - tcx.hir().local_def_id_to_hir_id(adt.did().expect_local()), + tcx.local_def_id_to_hir_id(adt.did().expect_local()), span, "zero-sized fields in `repr(transparent)` cannot \ contain external non-exhaustive types", diff --git a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs index d93bb48e0fe3..16fd1a951b5a 100644 --- a/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs +++ b/compiler/rustc_hir_analysis/src/check/compare_impl_item.rs @@ -380,7 +380,7 @@ fn compare_method_predicate_entailment<'tcx>( if !errors.is_empty() { match check_implied_wf { CheckImpliedWfMode::Check => { - let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); + let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id); return compare_method_predicate_entailment( tcx, impl_m, @@ -410,7 +410,7 @@ fn compare_method_predicate_entailment<'tcx>( if !errors.is_empty() { // FIXME(compiler-errors): This can be simplified when IMPLIED_BOUNDS_ENTAILMENT // becomes a hard error (i.e. ideally we'd just call `resolve_regions_and_report_errors` - let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); + let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id); match check_implied_wf { CheckImpliedWfMode::Check => { return compare_method_predicate_entailment( @@ -667,7 +667,7 @@ pub(super) fn collect_return_position_impl_trait_in_trait_tys<'tcx>( let trait_to_impl_args = impl_trait_ref.args; - let impl_m_hir_id = tcx.hir().local_def_id_to_hir_id(impl_m_def_id); + let impl_m_hir_id = tcx.local_def_id_to_hir_id(impl_m_def_id); let return_span = tcx.hir().fn_decl_by_hir_id(impl_m_hir_id).unwrap().output.span(); let cause = ObligationCause::new( return_span, diff --git a/compiler/rustc_hir_analysis/src/check/entry.rs b/compiler/rustc_hir_analysis/src/check/entry.rs index 6681292c93d1..947e50d31610 100644 --- a/compiler/rustc_hir_analysis/src/check/entry.rs +++ b/compiler/rustc_hir_analysis/src/check/entry.rs @@ -42,7 +42,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { if !def_id.is_local() { return None; } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local()); match tcx.hir().find(hir_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => { generics.params.is_empty().not().then_some(generics.span) @@ -57,7 +57,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { if !def_id.is_local() { return None; } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local()); match tcx.hir().find(hir_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(_, generics, _), .. })) => { Some(generics.where_clause_span) @@ -79,7 +79,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { if !def_id.is_local() { return None; } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = tcx.local_def_id_to_hir_id(def_id.expect_local()); match tcx.hir().find(hir_id) { Some(Node::Item(hir::Item { kind: hir::ItemKind::Fn(fn_sig, _, _), .. })) => { Some(fn_sig.decl.output.span()) @@ -194,7 +194,7 @@ fn check_main_fn_ty(tcx: TyCtxt<'_>, main_def_id: DefId) { fn check_start_fn_ty(tcx: TyCtxt<'_>, start_def_id: DefId) { let start_def_id = start_def_id.expect_local(); - let start_id = tcx.hir().local_def_id_to_hir_id(start_def_id); + let start_id = tcx.local_def_id_to_hir_id(start_def_id); let start_span = tcx.def_span(start_def_id); let start_t = tcx.type_of(start_def_id).instantiate_identity(); match start_t.kind() { diff --git a/compiler/rustc_hir_analysis/src/check/mod.rs b/compiler/rustc_hir_analysis/src/check/mod.rs index 15c5558fc0b0..a81a2037214d 100644 --- a/compiler/rustc_hir_analysis/src/check/mod.rs +++ b/compiler/rustc_hir_analysis/src/check/mod.rs @@ -128,7 +128,7 @@ fn get_owner_return_paths( tcx: TyCtxt<'_>, def_id: LocalDefId, ) -> Option<(LocalDefId, ReturnsVisitor<'_>)> { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let parent_id = tcx.hir().get_parent_item(hir_id).def_id; tcx.hir().find_by_def_id(parent_id).and_then(|node| node.body_id()).map(|body_id| { let body = tcx.hir().body(body_id); diff --git a/compiler/rustc_hir_analysis/src/coherence/orphan.rs b/compiler/rustc_hir_analysis/src/coherence/orphan.rs index 7c1086bf4b4c..46f77780a521 100644 --- a/compiler/rustc_hir_analysis/src/coherence/orphan.rs +++ b/compiler/rustc_hir_analysis/src/coherence/orphan.rs @@ -497,7 +497,7 @@ fn lint_auto_trait_impl<'tcx>( tcx.struct_span_lint_hir( lint::builtin::SUSPICIOUS_AUTO_TRAIT_IMPLS, - tcx.hir().local_def_id_to_hir_id(impl_def_id), + tcx.local_def_id_to_hir_id(impl_def_id), tcx.def_span(impl_def_id), DelayDm(|| { format!( diff --git a/compiler/rustc_hir_analysis/src/collect.rs b/compiler/rustc_hir_analysis/src/collect.rs index 60bd7e1bdc10..0a1b8c8eea58 100644 --- a/compiler/rustc_hir_analysis/src/collect.rs +++ b/compiler/rustc_hir_analysis/src/collect.rs @@ -350,7 +350,7 @@ impl<'tcx> ItemCtxt<'tcx> { } pub fn hir_id(&self) -> hir::HirId { - self.tcx.hir().local_def_id_to_hir_id(self.item_def_id) + self.tcx.local_def_id_to_hir_id(self.item_def_id) } pub fn node(&self) -> hir::Node<'tcx> { @@ -835,7 +835,7 @@ fn convert_variant( fn adt_def(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AdtDef<'_> { use rustc_hir::*; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let Node::Item(item) = tcx.hir().get(hir_id) else { bug!(); }; @@ -1101,7 +1101,7 @@ fn fn_sig(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder( def_id: LocalDefId, icx: &ItemCtxt<'tcx>, ) -> ty::PolyFnSig<'tcx> { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); match get_infer_ret_ty(&sig.decl.output) { Some(ty) => { @@ -1519,7 +1519,7 @@ fn compute_sig_of_foreign_fn_decl<'tcx>( } else { hir::Unsafety::Unsafe }; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let fty = ItemCtxt::new(tcx, def_id).astconv().ty_of_fn(hir_id, unsafety, abi, decl, None, None); diff --git a/compiler/rustc_hir_analysis/src/collect/generics_of.rs b/compiler/rustc_hir_analysis/src/collect/generics_of.rs index 97f60c986751..9fc994dfe50c 100644 --- a/compiler/rustc_hir_analysis/src/collect/generics_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/generics_of.rs @@ -14,7 +14,7 @@ use rustc_span::{sym, Span}; pub(super) fn generics_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Generics { use rustc_hir::*; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir().get(hir_id); let parent_def_id = match node { diff --git a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs index d746e6dea755..4d0fd2b691a9 100644 --- a/compiler/rustc_hir_analysis/src/collect/item_bounds.rs +++ b/compiler/rustc_hir_analysis/src/collect/item_bounds.rs @@ -105,7 +105,7 @@ pub(super) fn explicit_item_bounds( None => {} } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let bounds = match tcx.hir().get(hir_id) { hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Type(bounds, _), diff --git a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs index 92c383f37036..ca9443225e29 100644 --- a/compiler/rustc_hir_analysis/src/collect/predicates_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/predicates_of.rs @@ -134,7 +134,7 @@ fn gather_explicit_predicates_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Gen None => {} } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir().get(hir_id); let mut is_trait = None; @@ -412,7 +412,7 @@ fn const_evaluatable_predicates_of( } } - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir().get(hir_id); let mut collector = ConstCollector { tcx, preds: FxIndexSet::default() }; @@ -503,7 +503,7 @@ pub(super) fn explicit_predicates_of<'tcx>( } } else { if matches!(def_kind, DefKind::AnonConst) && tcx.features().generic_const_exprs { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let parent_def_id = tcx.hir().get_parent_item(hir_id); if let Some(defaulted_param_def_id) = @@ -571,7 +571,7 @@ pub(super) fn explicit_predicates_of<'tcx>( // To fix this, we call `explicit_predicates_of` directly on `foo`, the parent's parent. // In the above example this is `foo::{opaque#0}` or `impl Iterator` - let parent_hir_id = tcx.hir().local_def_id_to_hir_id(parent_def_id.def_id); + let parent_hir_id = tcx.local_def_id_to_hir_id(parent_def_id.def_id); // In the above example this is the function `foo` let item_def_id = tcx.hir().get_parent_item(parent_hir_id); @@ -631,7 +631,7 @@ pub(super) fn implied_predicates_with_filter( return tcx.super_predicates_of(trait_def_id); }; - let trait_hir_id = tcx.hir().local_def_id_to_hir_id(trait_def_id); + let trait_hir_id = tcx.local_def_id_to_hir_id(trait_def_id); let Node::Item(item) = tcx.hir().get(trait_hir_id) else { bug!("trait_node_id {} is not an item", trait_hir_id); @@ -691,7 +691,7 @@ pub(super) fn type_param_predicates( // written inline like `` or in a where-clause like // `where T: Foo`. - let param_id = tcx.hir().local_def_id_to_hir_id(def_id); + let param_id = tcx.local_def_id_to_hir_id(def_id); let param_owner = tcx.hir().ty_param_owner(def_id); let generics = tcx.generics_of(param_owner); let index = generics.param_def_id_to_index[&def_id.to_def_id()]; @@ -712,7 +712,7 @@ pub(super) fn type_param_predicates( .unwrap_or_default(); let mut extend = None; - let item_hir_id = tcx.hir().local_def_id_to_hir_id(item_def_id); + let item_hir_id = tcx.local_def_id_to_hir_id(item_def_id); let ast_generics = match tcx.hir().get(item_hir_id) { Node::TraitItem(item) => item.generics, diff --git a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs index bfabf967ebcc..e49bd0917a80 100644 --- a/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs +++ b/compiler/rustc_hir_analysis/src/collect/resolve_bound_vars.rs @@ -295,7 +295,7 @@ fn late_arg_as_bound_arg<'tcx>( ) -> ty::BoundVariableKind { match arg { ResolvedArg::LateBound(_, _, def_id) => { - let name = tcx.hir().name(tcx.hir().local_def_id_to_hir_id(def_id.expect_local())); + let name = tcx.hir().name(tcx.local_def_id_to_hir_id(def_id.expect_local())); match param.kind { GenericParamKind::Lifetime { .. } => { ty::BoundVariableKind::Region(ty::BrNamed(*def_id, name)) @@ -733,7 +733,7 @@ impl<'a, 'tcx> Visitor<'tcx> for BoundVarContext<'a, 'tcx> { let def = self.map.defs.get(&lifetime.hir_id).cloned(); let Some(ResolvedArg::LateBound(_, _, def_id)) = def else { continue }; let Some(def_id) = def_id.as_local() else { continue }; - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = self.tcx.local_def_id_to_hir_id(def_id); // Ensure that the parent of the def is an item, not HRTB let parent_id = self.tcx.hir().parent_id(hir_id); if !parent_id.is_owner() { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of.rs b/compiler/rustc_hir_analysis/src/collect/type_of.rs index d7bd2a7b17fc..c4fc4dda069a 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of.rs @@ -18,7 +18,7 @@ mod opaque; fn anon_const_type_of<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Ty<'tcx> { use hir::*; use rustc_middle::ty::Ty; - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let Node::AnonConst(_) = tcx.hir().get(hir_id) else { panic!() }; @@ -350,7 +350,7 @@ pub(super) fn type_of(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::EarlyBinder match item.kind { ItemKind::OpaqueTy(OpaqueTy { diff --git a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs index e8ab2651d728..f11a953536dc 100644 --- a/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs +++ b/compiler/rustc_hir_analysis/src/collect/type_of/opaque.rs @@ -41,7 +41,7 @@ pub fn test_opaque_hidden_types(tcx: TyCtxt<'_>) { /// ``` #[instrument(skip(tcx), level = "debug")] pub(super) fn find_opaque_ty_constraints_for_tait(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Ty<'_> { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let scope = tcx.hir().get_defining_scope(hir_id); let mut locator = TaitConstraintLocator { def_id, tcx, found: None, typeck_types: vec![] }; @@ -278,7 +278,7 @@ pub(super) fn find_opaque_ty_constraints_for_rpit<'tcx>( let mir_opaque_ty = tcx.mir_borrowck(owner_def_id).concrete_opaque_types.get(&def_id).copied(); if let Some(mir_opaque_ty) = mir_opaque_ty { - let scope = tcx.hir().local_def_id_to_hir_id(owner_def_id); + let scope = tcx.local_def_id_to_hir_id(owner_def_id); debug!(?scope); let mut locator = RpitConstraintChecker { def_id, tcx, found: mir_opaque_ty }; diff --git a/compiler/rustc_hir_analysis/src/hir_wf_check.rs b/compiler/rustc_hir_analysis/src/hir_wf_check.rs index 55c01d2084b8..f22b836b42b9 100644 --- a/compiler/rustc_hir_analysis/src/hir_wf_check.rs +++ b/compiler/rustc_hir_analysis/src/hir_wf_check.rs @@ -25,7 +25,7 @@ fn diagnostic_hir_wf_check<'tcx>( WellFormedLoc::Ty(def_id) => def_id, WellFormedLoc::Param { function, param_idx: _ } => function, }; - let hir_id = hir.local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); // HIR wfcheck should only ever happen as part of improving an existing error tcx.sess diff --git a/compiler/rustc_hir_analysis/src/outlives/mod.rs b/compiler/rustc_hir_analysis/src/outlives/mod.rs index be9d076bd6eb..c065f6e7e881 100644 --- a/compiler/rustc_hir_analysis/src/outlives/mod.rs +++ b/compiler/rustc_hir_analysis/src/outlives/mod.rs @@ -18,7 +18,7 @@ pub fn provide(providers: &mut Providers) { } fn inferred_outlives_of(tcx: TyCtxt<'_>, item_def_id: LocalDefId) -> &[(ty::Clause<'_>, Span)] { - let id = tcx.hir().local_def_id_to_hir_id(item_def_id); + let id = tcx.local_def_id_to_hir_id(item_def_id); if matches!(tcx.def_kind(item_def_id), hir::def::DefKind::AnonConst) && tcx.features().generic_const_exprs diff --git a/compiler/rustc_hir_typeck/src/check.rs b/compiler/rustc_hir_typeck/src/check.rs index d13ae2c2094c..0cd1ae2dbfe5 100644 --- a/compiler/rustc_hir_typeck/src/check.rs +++ b/compiler/rustc_hir_typeck/src/check.rs @@ -34,7 +34,7 @@ pub(super) fn check_fn<'a, 'tcx>( can_be_coroutine: Option, params_can_be_unsized: bool, ) -> Option> { - let fn_id = fcx.tcx.hir().local_def_id_to_hir_id(fn_def_id); + let fn_id = fcx.tcx.local_def_id_to_hir_id(fn_def_id); let tcx = fcx.tcx; let hir = tcx.hir(); diff --git a/compiler/rustc_hir_typeck/src/closure.rs b/compiler/rustc_hir_typeck/src/closure.rs index d818bb1dfaa9..cb36d510149f 100644 --- a/compiler/rustc_hir_typeck/src/closure.rs +++ b/compiler/rustc_hir_typeck/src/closure.rs @@ -624,7 +624,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { trace!("decl = {:#?}", decl); debug!(?body.coroutine_kind); - let hir_id = self.tcx.hir().local_def_id_to_hir_id(expr_def_id); + let hir_id = self.tcx.local_def_id_to_hir_id(expr_def_id); let bound_vars = self.tcx.late_bound_vars(hir_id); // First, convert the types that the user supplied (if any). diff --git a/compiler/rustc_hir_typeck/src/demand.rs b/compiler/rustc_hir_typeck/src/demand.rs index 41d88e246af8..33d14476b2cd 100644 --- a/compiler/rustc_hir_typeck/src/demand.rs +++ b/compiler/rustc_hir_typeck/src/demand.rs @@ -883,7 +883,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let container_id = pick.item.container_id(self.tcx); let container = with_no_trimmed_paths!(self.tcx.def_path_str(container_id)); for def_id in pick.import_ids { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = self.tcx.local_def_id_to_hir_id(def_id); path_span.push_span_label( self.tcx.hir().span(hir_id), format!("`{container}` imported here"), diff --git a/compiler/rustc_hir_typeck/src/expr.rs b/compiler/rustc_hir_typeck/src/expr.rs index e5254dc49c7e..f16269795e98 100644 --- a/compiler/rustc_hir_typeck/src/expr.rs +++ b/compiler/rustc_hir_typeck/src/expr.rs @@ -2344,7 +2344,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match deref_base_ty.kind() { ty::Adt(base_def, args) if !base_def.is_enum() => { debug!("struct named {:?}", deref_base_ty); - let body_hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + let body_hir_id = self.tcx.local_def_id_to_hir_id(self.body_id); let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope(field, base_def.did(), body_hir_id); let fields = &base_def.non_enum_variant().fields; @@ -2691,7 +2691,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { } let param_def_id = generic_param.def_id; let param_hir_id = match param_def_id.as_local() { - Some(x) => self.tcx.hir().local_def_id_to_hir_id(x), + Some(x) => self.tcx.local_def_id_to_hir_id(x), None => return, }; let param_span = self.tcx.hir().span(param_hir_id); @@ -3268,7 +3268,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { match container.kind() { ty::Adt(container_def, args) if container_def.is_enum() => { - let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + let block = self.tcx.local_def_id_to_hir_id(self.body_id); let (ident, _def_scope) = self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); @@ -3350,7 +3350,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { continue; } ty::Adt(container_def, args) => { - let block = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + let block = self.tcx.local_def_id_to_hir_id(self.body_id); let (ident, def_scope) = self.tcx.adjust_ident_and_get_scope(field, container_def.did(), block); diff --git a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs index 587638f958a4..d7cf6dba9aac 100644 --- a/compiler/rustc_hir_typeck/src/expr_use_visitor.rs +++ b/compiler/rustc_hir_typeck/src/expr_use_visitor.rs @@ -848,7 +848,7 @@ impl<'a, 'tcx> ExprUseVisitor<'a, 'tcx> { // be a local variable PlaceBase::Local(*var_hir_id) }; - let closure_hir_id = tcx.hir().local_def_id_to_hir_id(closure_def_id); + let closure_hir_id = tcx.local_def_id_to_hir_id(closure_def_id); let place_with_id = PlaceWithHirId::new( capture_info .path_expr_id diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs index 47ac7007a778..6660bea03d8b 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/suggestions.rs @@ -43,7 +43,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.typeck_results .borrow() .liberated_fn_sigs() - .get(self.tcx.hir().local_def_id_to_hir_id(self.body_id)) + .get(self.tcx.local_def_id_to_hir_id(self.body_id)) .copied() } diff --git a/compiler/rustc_hir_typeck/src/inherited.rs b/compiler/rustc_hir_typeck/src/inherited.rs index efd0b8577cf9..281074a85192 100644 --- a/compiler/rustc_hir_typeck/src/inherited.rs +++ b/compiler/rustc_hir_typeck/src/inherited.rs @@ -75,7 +75,7 @@ impl<'tcx> Deref for Inherited<'tcx> { impl<'tcx> Inherited<'tcx> { pub fn new(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> Self { - let hir_owner = tcx.hir().local_def_id_to_hir_id(def_id).owner; + let hir_owner = tcx.local_def_id_to_hir_id(def_id).owner; let infcx = tcx .infer_ctxt() diff --git a/compiler/rustc_hir_typeck/src/lib.rs b/compiler/rustc_hir_typeck/src/lib.rs index f43e1c575a04..b4591e7f4f71 100644 --- a/compiler/rustc_hir_typeck/src/lib.rs +++ b/compiler/rustc_hir_typeck/src/lib.rs @@ -146,7 +146,7 @@ fn typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tc /// Currently only used for type inference of `static`s and `const`s to avoid type cycle errors. fn diagnostic_only_typeck<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &ty::TypeckResults<'tcx> { let fallback = move || { - let span = tcx.hir().span(tcx.hir().local_def_id_to_hir_id(def_id)); + let span = tcx.hir().span(tcx.local_def_id_to_hir_id(def_id)); Ty::new_error_with_message(tcx, span, "diagnostic only typeck table used") }; typeck_with_fallback(tcx, def_id, fallback) @@ -165,7 +165,7 @@ fn typeck_with_fallback<'tcx>( return tcx.typeck(typeck_root_def_id); } - let id = tcx.hir().local_def_id_to_hir_id(def_id); + let id = tcx.local_def_id_to_hir_id(def_id); let node = tcx.hir().get(id); let span = tcx.hir().span(id); diff --git a/compiler/rustc_hir_typeck/src/method/probe.rs b/compiler/rustc_hir_typeck/src/method/probe.rs index 89196e4a0ac7..7d83f4a12b1f 100644 --- a/compiler/rustc_hir_typeck/src/method/probe.rs +++ b/compiler/rustc_hir_typeck/src/method/probe.rs @@ -619,7 +619,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { fn push_candidate(&mut self, candidate: Candidate<'tcx>, is_inherent: bool) { let is_accessible = if let Some(name) = self.method_name { let item = candidate.item; - let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.body_id); + let hir_id = self.tcx.local_def_id_to_hir_id(self.body_id); let def_scope = self.tcx.adjust_ident_and_get_scope(name, item.container_id(self.tcx), hir_id).1; item.visibility(self.tcx).is_accessible_from(def_scope, self.tcx) @@ -1939,7 +1939,7 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { let Some(local_def_id) = def_id.as_local() else { return false; }; - let hir_id = self.fcx.tcx.hir().local_def_id_to_hir_id(local_def_id); + let hir_id = self.fcx.tcx.local_def_id_to_hir_id(local_def_id); let attrs = self.fcx.tcx.hir().attrs(hir_id); for attr in attrs { let sym::doc = attr.name_or_empty() else { diff --git a/compiler/rustc_hir_typeck/src/method/suggest.rs b/compiler/rustc_hir_typeck/src/method/suggest.rs index 3b96cd96d2ed..a7764f4ff965 100644 --- a/compiler/rustc_hir_typeck/src/method/suggest.rs +++ b/compiler/rustc_hir_typeck/src/method/suggest.rs @@ -2867,7 +2867,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let id = item .def_id .as_local() - .map(|def_id| self.tcx.hir().local_def_id_to_hir_id(def_id)); + .map(|def_id| self.tcx.local_def_id_to_hir_id(def_id)); if let Some(hir::Node::TraitItem(hir::TraitItem { kind: hir::TraitItemKind::Fn(fn_sig, method), .. @@ -2957,7 +2957,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let type_param = generics.type_param(param, self.tcx); let hir = self.tcx.hir(); if let Some(def_id) = type_param.def_id.as_local() { - let id = hir.local_def_id_to_hir_id(def_id); + let id = self.tcx.local_def_id_to_hir_id(def_id); // Get the `hir::Param` to verify whether it already has any bounds. // We do this to avoid suggesting code that ends up as `T: FooBar`, // instead we suggest `T: Foo + Bar` in that case. diff --git a/compiler/rustc_hir_typeck/src/upvar.rs b/compiler/rustc_hir_typeck/src/upvar.rs index 17b81acd506a..3a0f46c3a8c7 100644 --- a/compiler/rustc_hir_typeck/src/upvar.rs +++ b/compiler/rustc_hir_typeck/src/upvar.rs @@ -221,7 +221,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { self.compute_min_captures(closure_def_id, capture_information, span); - let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id); + let closure_hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id); if should_do_rust_2021_incompatible_closure_captures_analysis(self.tcx, closure_hir_id) { self.perform_2229_migration_analysis(closure_def_id, body_id, capture_clause, span); @@ -763,7 +763,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { let (migration_string, migrated_variables_concat) = migration_suggestion_for_2229(self.tcx, &need_migrations); - let closure_hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id); + let closure_hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id); let closure_head_span = self.tcx.def_span(closure_def_id); self.tcx.struct_span_lint_hir( lint::builtin::RUST_2021_INCOMPATIBLE_CLOSURE_CAPTURES, diff --git a/compiler/rustc_hir_typeck/src/writeback.rs b/compiler/rustc_hir_typeck/src/writeback.rs index 2462ac936326..fc635a8da2ee 100644 --- a/compiler/rustc_hir_typeck/src/writeback.rs +++ b/compiler/rustc_hir_typeck/src/writeback.rs @@ -47,7 +47,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { // Type only exists for constants and statics, not functions. match self.tcx.hir().body_owner_kind(item_def_id) { hir::BodyOwnerKind::Const { .. } | hir::BodyOwnerKind::Static(_) => { - let item_hir_id = self.tcx.hir().local_def_id_to_hir_id(item_def_id); + let item_hir_id = self.tcx.local_def_id_to_hir_id(item_def_id); wbcx.visit_node_id(body.value.span, item_hir_id); } hir::BodyOwnerKind::Closure | hir::BodyOwnerKind::Fn => (), @@ -382,7 +382,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { .to_sorted(hcx, false) .into_iter() .map(|(&closure_def_id, data)| { - let closure_hir_id = self.tcx().hir().local_def_id_to_hir_id(closure_def_id); + let closure_hir_id = self.tcx().local_def_id_to_hir_id(closure_def_id); let data = self.resolve(*data, &closure_hir_id); (closure_def_id, data) }) @@ -407,7 +407,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { .map(|captured_place| { let locatable = captured_place.info.path_expr_id.unwrap_or_else(|| { - self.tcx().hir().local_def_id_to_hir_id(closure_def_id) + self.tcx().local_def_id_to_hir_id(closure_def_id) }); self.resolve(captured_place.clone(), &locatable) }) @@ -433,7 +433,7 @@ impl<'cx, 'tcx> WritebackCx<'cx, 'tcx> { let resolved_fake_reads = fake_reads .iter() .map(|(place, cause, hir_id)| { - let locatable = self.tcx().hir().local_def_id_to_hir_id(closure_def_id); + let locatable = self.tcx().local_def_id_to_hir_id(closure_def_id); let resolved_fake_read = self.resolve(place.clone(), &locatable); (resolved_fake_read, *cause, *hir_id) }) diff --git a/compiler/rustc_incremental/src/assert_dep_graph.rs b/compiler/rustc_incremental/src/assert_dep_graph.rs index 3f30b3f2b4c0..a5e0654c81df 100644 --- a/compiler/rustc_incremental/src/assert_dep_graph.rs +++ b/compiler/rustc_incremental/src/assert_dep_graph.rs @@ -122,7 +122,7 @@ impl<'tcx> IfThisChanged<'tcx> { fn process_attrs(&mut self, def_id: LocalDefId) { let def_path_hash = self.tcx.def_path_hash(def_id.to_def_id()); - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = self.tcx.local_def_id_to_hir_id(def_id); let attrs = self.tcx.hir().attrs(hir_id); for attr in attrs { if attr.has_name(sym::rustc_if_this_changed) { diff --git a/compiler/rustc_infer/src/errors/mod.rs b/compiler/rustc_infer/src/errors/mod.rs index 3ff1a5c0c14b..6a220243266d 100644 --- a/compiler/rustc_infer/src/errors/mod.rs +++ b/compiler/rustc_infer/src/errors/mod.rs @@ -363,7 +363,7 @@ impl AddToDiagnostic for AddLifetimeParamsSuggestion<'_> { return false; }; - let hir_id = self.tcx.hir().local_def_id_to_hir_id(anon_reg.def_id); + let hir_id = self.tcx.local_def_id_to_hir_id(anon_reg.def_id); let node = self.tcx.hir().get(hir_id); let is_impl = matches!(&node, hir::Node::ImplItem(_)); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs index 5687d85d24a3..ab928232d745 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/find_anon_type.rs @@ -26,7 +26,7 @@ pub fn find_anon_type<'tcx>( br: &ty::BoundRegionKind, ) -> Option<(&'tcx hir::Ty<'tcx>, &'tcx hir::FnSig<'tcx>)> { let anon_reg = tcx.is_suitable_region(region)?; - let hir_id = tcx.hir().local_def_id_to_hir_id(anon_reg.def_id); + let hir_id = tcx.local_def_id_to_hir_id(anon_reg.def_id); let fn_sig = tcx.hir().get(hir_id).fn_sig()?; fn_sig diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs index cb51254a14b0..b16d5c509e00 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/trait_impl_difference.rs @@ -101,7 +101,7 @@ impl<'a, 'tcx> NiceRegionError<'a, 'tcx> { ty::AssocKind::Fn => { let hir = self.tcx().hir(); if let Some(hir_id) = - assoc_item.def_id.as_local().map(|id| hir.local_def_id_to_hir_id(id)) + assoc_item.def_id.as_local().map(|id| self.tcx().local_def_id_to_hir_id(id)) { if let Some(decl) = hir.fn_decl_by_hir_id(hir_id) { visitor.visit_fn_decl(decl); diff --git a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs index b26ce464486a..155c03560256 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/nice_region_error/util.rs @@ -50,7 +50,7 @@ pub fn find_param_with_region<'tcx>( let hir = &tcx.hir(); let def_id = id.as_local()?; - let hir_id = hir.local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); // FIXME: use def_kind // Don't perform this on closures diff --git a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs index 59e9cbf7da6a..b93fe02aaeab 100644 --- a/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs +++ b/compiler/rustc_infer/src/infer/error_reporting/note_and_explain.rs @@ -105,7 +105,7 @@ impl<'tcx> TypeErrCtxt<'_, 'tcx> { ); } p_def_id.as_local().and_then(|id| { - let local_id = tcx.hir().local_def_id_to_hir_id(id); + let local_id = tcx.local_def_id_to_hir_id(id); let generics = tcx.hir().find_parent(local_id)?.generics()?; Some((id, generics)) }) diff --git a/compiler/rustc_infer/src/infer/opaque_types.rs b/compiler/rustc_infer/src/infer/opaque_types.rs index 4e2cd00613b0..82ab19550536 100644 --- a/compiler/rustc_infer/src/infer/opaque_types.rs +++ b/compiler/rustc_infer/src/infer/opaque_types.rs @@ -374,7 +374,7 @@ impl<'tcx> InferCtxt<'tcx> { /// in its defining scope. #[instrument(skip(self), level = "trace", ret)] pub fn opaque_type_origin(&self, def_id: LocalDefId) -> Option { - let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let opaque_hir_id = self.tcx.local_def_id_to_hir_id(def_id); let parent_def_id = match self.defining_use_anchor { DefiningAnchor::Bubble | DefiningAnchor::Error => return None, DefiningAnchor::Bind(bind) => bind, @@ -671,7 +671,7 @@ impl<'tcx> InferCtxt<'tcx> { /// and `opaque_hir_id` is the `HirId` of the definition of the opaque type `Baz`. /// For the above example, this function returns `true` for `f1` and `false` for `f2`. fn may_define_opaque_type(tcx: TyCtxt<'_>, def_id: LocalDefId, opaque_hir_id: hir::HirId) -> bool { - let mut hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let mut hir_id = tcx.local_def_id_to_hir_id(def_id); // Named opaque types can be defined by any siblings or children of siblings. let scope = tcx.hir().get_defining_scope(opaque_hir_id); diff --git a/compiler/rustc_lint/src/builtin.rs b/compiler/rustc_lint/src/builtin.rs index a1c5cfacc82b..8932200c5b7b 100644 --- a/compiler/rustc_lint/src/builtin.rs +++ b/compiler/rustc_lint/src/builtin.rs @@ -507,7 +507,7 @@ impl MissingDoc { } } - let attrs = cx.tcx.hir().attrs(cx.tcx.hir().local_def_id_to_hir_id(def_id)); + let attrs = cx.tcx.hir().attrs(cx.tcx.local_def_id_to_hir_id(def_id)); let has_doc = attrs.iter().any(has_doc); if !has_doc { cx.emit_spanned_lint( diff --git a/compiler/rustc_lint/src/late.rs b/compiler/rustc_lint/src/late.rs index 4f0cf5c52542..caa015565914 100644 --- a/compiler/rustc_lint/src/late.rs +++ b/compiler/rustc_lint/src/late.rs @@ -356,7 +356,7 @@ pub fn late_lint_mod<'tcx, T: LateLintPass<'tcx> + 'tcx>( cached_typeck_results: Cell::new(None), param_env: ty::ParamEnv::empty(), effective_visibilities: tcx.effective_visibilities(()), - last_node_with_lint_attrs: tcx.hir().local_def_id_to_hir_id(module_def_id), + last_node_with_lint_attrs: tcx.local_def_id_to_hir_id(module_def_id.into()), generics: None, only_module: true, }; diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 562eaf213d22..7c5d0eaf9276 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -1811,7 +1811,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { // so we manually encode just the information that we need for &proc_macro in &tcx.resolutions(()).proc_macros { let id = proc_macro; - let proc_macro = hir.local_def_id_to_hir_id(proc_macro); + let proc_macro = tcx.local_def_id_to_hir_id(proc_macro); let mut name = hir.name(proc_macro); let span = hir.span(proc_macro); // Proc-macros may have attributes like `#[allow_internal_unstable]`, diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index c1c2ac22bd39..9103187acf34 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -116,7 +116,7 @@ impl<'hir> Iterator for ParentOwnerIterator<'hir> { let parent_id = parent_id.map_or(CRATE_OWNER_ID, |local_def_index| { let def_id = LocalDefId { local_def_index }; - self.map.local_def_id_to_hir_id(def_id).owner + self.map.tcx.local_def_id_to_hir_id(def_id).owner }); self.current_id = HirId::make_owner(parent_id.def_id); @@ -168,14 +168,9 @@ impl<'hir> Map<'hir> { self.tcx.definitions_untracked().def_path_hash(def_id) } - #[inline] - pub fn local_def_id_to_hir_id(self, def_id: impl Into) -> HirId { - self.tcx.local_def_id_to_hir_id(def_id.into()) - } - /// Do not call this function directly. The query should be called. pub(super) fn def_kind(self, local_def_id: LocalDefId) -> DefKind { - let hir_id = self.local_def_id_to_hir_id(local_def_id); + let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id); let node = match self.find(hir_id) { Some(node) => node, None => match self.def_key(local_def_id).disambiguated_data.data { @@ -415,7 +410,7 @@ impl<'hir> Map<'hir> { #[track_caller] pub fn body_owned_by(self, id: LocalDefId) -> BodyId { self.maybe_body_owned_by(id).unwrap_or_else(|| { - let hir_id = self.local_def_id_to_hir_id(id); + let hir_id = self.tcx.local_def_id_to_hir_id(id); span_bug!( self.span(hir_id), "body_owned_by: {} has no associated body", diff --git a/compiler/rustc_middle/src/hir/mod.rs b/compiler/rustc_middle/src/hir/mod.rs index af7a2efe35a8..bf652fc277ab 100644 --- a/compiler/rustc_middle/src/hir/mod.rs +++ b/compiler/rustc_middle/src/hir/mod.rs @@ -166,7 +166,7 @@ pub fn provide(providers: &mut Providers) { providers.hir_owner_parent = |tcx, id| { // Accessing the local_parent is ok since its value is hashed as part of `id`'s DefPathHash. tcx.opt_local_parent(id.def_id).map_or(CRATE_HIR_ID, |parent| { - let mut parent_hir_id = tcx.hir().local_def_id_to_hir_id(parent); + let mut parent_hir_id = tcx.local_def_id_to_hir_id(parent); parent_hir_id.local_id = tcx.hir_crate(()).owners[parent_hir_id.owner.def_id].unwrap().parenting[&id.def_id]; parent_hir_id @@ -176,16 +176,16 @@ pub fn provide(providers: &mut Providers) { tcx.hir_crate(()).owners[id.def_id].as_owner().map_or(AttributeMap::EMPTY, |o| &o.attrs) }; providers.def_span = |tcx, def_id| { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); tcx.hir().opt_span(hir_id).unwrap_or(DUMMY_SP) }; providers.def_ident_span = |tcx, def_id| { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); tcx.hir().opt_ident_span(hir_id) }; providers.fn_arg_names = |tcx, def_id| { let hir = tcx.hir(); - let hir_id = hir.local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); if let Some(body_id) = hir.maybe_body_owned_by(def_id) { tcx.arena.alloc_from_iter(hir.body_param_names(body_id)) } else if let Node::TraitItem(&TraitItem { diff --git a/compiler/rustc_middle/src/mir/interpret/queries.rs b/compiler/rustc_middle/src/mir/interpret/queries.rs index fbf6403eabe3..34068a9da37e 100644 --- a/compiler/rustc_middle/src/mir/interpret/queries.rs +++ b/compiler/rustc_middle/src/mir/interpret/queries.rs @@ -110,7 +110,7 @@ impl<'tcx> TyCtxt<'tcx> { let Some(local_def_id) = ct.def.as_local() else { return }; self.struct_span_lint_hir( lint::builtin::CONST_EVALUATABLE_UNCHECKED, - self.hir().local_def_id_to_hir_id(local_def_id), + self.local_def_id_to_hir_id(local_def_id), self.def_span(ct.def), "cannot use constants which depend on generic parameters in types", |err| err, diff --git a/compiler/rustc_middle/src/traits/specialization_graph.rs b/compiler/rustc_middle/src/traits/specialization_graph.rs index e48b46d12c48..6db427064d16 100644 --- a/compiler/rustc_middle/src/traits/specialization_graph.rs +++ b/compiler/rustc_middle/src/traits/specialization_graph.rs @@ -72,7 +72,7 @@ impl OverlapMode { .as_local() .into_iter() .flat_map(|local_def_id| { - tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(local_def_id)) + tcx.hir().attrs(tcx.local_def_id_to_hir_id(local_def_id)) }) .find(|attr| attr.has_name(sym::rustc_strict_coherence)) .map(|attr| attr.span); diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 74bdd07a1c94..a355007d6203 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -262,7 +262,7 @@ fn closure_typeinfo<'tcx>(tcx: TyCtxt<'tcx>, def: LocalDefId) -> ClosureTypeInfo let user_provided_sig = typeck_results.user_provided_sigs[&def]; let captures = typeck_results.closure_min_captures_flattened(def); let captures = tcx.arena.alloc_from_iter(captures); - let hir_id = tcx.hir().local_def_id_to_hir_id(def); + let hir_id = tcx.local_def_id_to_hir_id(def); let kind_origin = typeck_results.closure_kind_origins().get(hir_id); ClosureTypeInfo { user_provided_sig, captures, kind_origin } } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3e24b7cce867..df5ac28130a7 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -1131,7 +1131,7 @@ impl<'tcx> TyCtxt<'tcx> { self, scope_def_id: LocalDefId, ) -> Vec<&'tcx hir::Ty<'tcx>> { - let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); + let hir_id = self.local_def_id_to_hir_id(scope_def_id); let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id) else { @@ -1150,7 +1150,7 @@ impl<'tcx> TyCtxt<'tcx> { self, scope_def_id: LocalDefId, ) -> Option<(Vec<&'tcx hir::Ty<'tcx>>, Span, Option)> { - let hir_id = self.hir().local_def_id_to_hir_id(scope_def_id); + let hir_id = self.local_def_id_to_hir_id(scope_def_id); let mut v = TraitObjectVisitor(vec![], self.hir()); // when the return type is a type alias if let Some(hir::FnDecl { output: hir::FnRetTy::Return(hir_output), .. }) = self.hir().fn_decl_by_hir_id(hir_id) diff --git a/compiler/rustc_middle/src/ty/mod.rs b/compiler/rustc_middle/src/ty/mod.rs index 1e50ccba770b..da93f7f8ae65 100644 --- a/compiler/rustc_middle/src/ty/mod.rs +++ b/compiler/rustc_middle/src/ty/mod.rs @@ -2273,7 +2273,7 @@ impl<'tcx> TyCtxt<'tcx> { // FIXME(@lcnr): Remove this function. pub fn get_attrs_unchecked(self, did: DefId) -> &'tcx [ast::Attribute] { if let Some(did) = did.as_local() { - self.hir().attrs(self.hir().local_def_id_to_hir_id(did)) + self.hir().attrs(self.local_def_id_to_hir_id(did)) } else { self.item_attrs(did) } @@ -2288,7 +2288,7 @@ impl<'tcx> TyCtxt<'tcx> { let did: DefId = did.into(); let filter_fn = move |a: &&ast::Attribute| a.has_name(attr); if let Some(did) = did.as_local() { - self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn) + self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) } else if cfg!(debug_assertions) && rustc_feature::is_builtin_only_local(attr) { bug!("tried to access the `only_local` attribute `{}` from an extern crate", attr); } else { @@ -2306,7 +2306,7 @@ impl<'tcx> TyCtxt<'tcx> { { let filter_fn = move |a: &&ast::Attribute| a.path_matches(attr); if let Some(did) = did.as_local() { - self.hir().attrs(self.hir().local_def_id_to_hir_id(did)).iter().filter(filter_fn) + self.hir().attrs(self.local_def_id_to_hir_id(did)).iter().filter(filter_fn) } else { self.item_attrs(did).iter().filter(filter_fn) } diff --git a/compiler/rustc_middle/src/values.rs b/compiler/rustc_middle/src/values.rs index 2b4ae3736269..8ccd3c1aba0c 100644 --- a/compiler/rustc_middle/src/values.rs +++ b/compiler/rustc_middle/src/values.rs @@ -154,7 +154,7 @@ pub fn recursive_type_error( let (_, field_id) = item_and_field_ids[i]; let (next_item_id, _) = item_and_field_ids[(i + 1) % cycle_len]; // Find the span(s) that contain the next item in the cycle - let hir_id = tcx.hir().local_def_id_to_hir_id(field_id); + let hir_id = tcx.local_def_id_to_hir_id(field_id); let hir::Node::Field(field) = tcx.hir().get(hir_id) else { bug!("expected field") }; let mut found = Vec::new(); find_item_ty_spans(tcx, field.ty, next_item_id, &mut found, representable_ids); diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 3d2396f33fc0..ad06db91e373 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -451,7 +451,7 @@ fn construct_fn<'tcx>( fn_sig: ty::FnSig<'tcx>, ) -> Body<'tcx> { let span = tcx.def_span(fn_def); - let fn_id = tcx.hir().local_def_id_to_hir_id(fn_def); + let fn_id = tcx.local_def_id_to_hir_id(fn_def); let coroutine_kind = tcx.coroutine_kind(fn_def); // The representation of thir for `-Zunpretty=thir-tree` relies on @@ -569,7 +569,7 @@ fn construct_const<'a, 'tcx>( expr: ExprId, const_ty: Ty<'tcx>, ) -> Body<'tcx> { - let hir_id = tcx.hir().local_def_id_to_hir_id(def); + let hir_id = tcx.local_def_id_to_hir_id(def); // Figure out what primary body this item has. let (span, const_ty_span) = match tcx.hir().get(hir_id) { @@ -622,7 +622,7 @@ fn construct_const<'a, 'tcx>( /// with type errors, but normal MIR construction can't handle that in general. fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) -> Body<'_> { let span = tcx.def_span(def_id); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let coroutine_kind = tcx.coroutine_kind(def_id); let (inputs, output, yield_ty) = match tcx.def_kind(def_id) { diff --git a/compiler/rustc_mir_build/src/check_unsafety.rs b/compiler/rustc_mir_build/src/check_unsafety.rs index db0efd1d12ef..bbaa02233e57 100644 --- a/compiler/rustc_mir_build/src/check_unsafety.rs +++ b/compiler/rustc_mir_build/src/check_unsafety.rs @@ -138,7 +138,7 @@ impl<'tcx> UnsafetyVisitor<'_, 'tcx> { // Runs all other queries that depend on THIR. self.tcx.ensure_with_value().mir_built(def); let inner_thir = &inner_thir.steal(); - let hir_context = self.tcx.hir().local_def_id_to_hir_id(def); + let hir_context = self.tcx.local_def_id_to_hir_id(def); let safety_context = mem::replace(&mut self.safety_context, SafetyContext::Safe); let mut inner_visitor = UnsafetyVisitor { thir: inner_thir, @@ -859,7 +859,7 @@ pub fn thir_check_unsafety(tcx: TyCtxt<'_>, def: LocalDefId) { return; } - let hir_id = tcx.hir().local_def_id_to_hir_id(def); + let hir_id = tcx.local_def_id_to_hir_id(def); let safety_context = tcx.hir().fn_sig_by_hir_id(hir_id).map_or(SafetyContext::Safe, |fn_sig| { if fn_sig.header.unsafety == hir::Unsafety::Unsafe { SafetyContext::UnsafeFn diff --git a/compiler/rustc_mir_build/src/lints.rs b/compiler/rustc_mir_build/src/lints.rs index acf4d6bc2a07..167b65328d11 100644 --- a/compiler/rustc_mir_build/src/lints.rs +++ b/compiler/rustc_mir_build/src/lints.rs @@ -52,7 +52,7 @@ fn check_recursion<'tcx>( vis.reachable_recursive_calls.sort(); let sp = tcx.def_span(def_id); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); tcx.emit_spanned_lint( UNCONDITIONAL_RECURSION, hir_id, diff --git a/compiler/rustc_mir_build/src/thir/cx/expr.rs b/compiler/rustc_mir_build/src/thir/cx/expr.rs index d3af1b7745ec..9759c72bf580 100644 --- a/compiler/rustc_mir_build/src/thir/cx/expr.rs +++ b/compiler/rustc_mir_build/src/thir/cx/expr.rs @@ -899,7 +899,7 @@ impl<'tcx> Cx<'tcx> { } Res::Def(DefKind::ConstParam, def_id) => { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id.expect_local()); + let hir_id = self.tcx.local_def_id_to_hir_id(def_id.expect_local()); let generics = self.tcx.generics_of(hir_id.owner); let index = generics.param_def_id_to_index[&def_id]; let name = self.tcx.hir().name(hir_id); diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 0427f66db287..708e0b31b9e4 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -29,7 +29,7 @@ pub(crate) fn thir_body( } let expr = cx.mirror_expr(body.value); - let owner_id = hir.local_def_id_to_hir_id(owner_def); + let owner_id = tcx.local_def_id_to_hir_id(owner_def); if let Some(fn_decl) = hir.fn_decl_by_hir_id(owner_id) { let closure_env_param = cx.closure_env_param(owner_def, owner_id); let explicit_params = cx.explicit_params(owner_id, fn_decl, body); @@ -72,7 +72,7 @@ impl<'tcx> Cx<'tcx> { fn new(tcx: TyCtxt<'tcx>, def: LocalDefId) -> Cx<'tcx> { let typeck_results = tcx.typeck(def); let hir = tcx.hir(); - let hir_id = hir.local_def_id_to_hir_id(def); + let hir_id = tcx.local_def_id_to_hir_id(def); let body_type = if hir.body_owner_kind(def).is_fn_or_closure() { // fetch the fully liberated fn signature (that is, all bound diff --git a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs index e402468f038e..806027139056 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/check_match.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/check_match.rs @@ -33,7 +33,7 @@ pub(crate) fn check_match(tcx: TyCtxt<'_>, def_id: LocalDefId) -> Result<(), Err tcx, thir: &*thir, param_env: tcx.param_env(def_id), - lint_level: tcx.hir().local_def_id_to_hir_id(def_id), + lint_level: tcx.local_def_id_to_hir_id(def_id), let_source: LetSource::None, pattern_arena: &pattern_arena, error: Ok(()), diff --git a/compiler/rustc_mir_transform/src/check_unsafety.rs b/compiler/rustc_mir_transform/src/check_unsafety.rs index cfcd5acb9e95..85447887cb0e 100644 --- a/compiler/rustc_mir_transform/src/check_unsafety.rs +++ b/compiler/rustc_mir_transform/src/check_unsafety.rs @@ -452,7 +452,7 @@ fn check_unused_unsafe( }; let body = tcx.hir().body(body_id); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let context = match tcx.hir().fn_sig_by_hir_id(hir_id) { Some(sig) if sig.header.unsafety == hir::Unsafety::Unsafe => Context::UnsafeFn(hir_id), _ => Context::Safe, @@ -568,7 +568,7 @@ pub fn check_unsafety(tcx: TyCtxt<'_>, def_id: LocalDefId) { errors::UnsafeOpInUnsafeFn { details, suggest_unsafe_block: suggest_unsafe_block.then(|| { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let fn_sig = tcx .hir() .fn_sig_by_hir_id(hir_id) diff --git a/compiler/rustc_passes/src/check_const.rs b/compiler/rustc_passes/src/check_const.rs index 22b80a60d42a..de96746e215c 100644 --- a/compiler/rustc_passes/src/check_const.rs +++ b/compiler/rustc_passes/src/check_const.rs @@ -110,7 +110,7 @@ impl<'tcx> CheckConstVisitor<'tcx> { // However, we cannot allow stable `const fn`s to use unstable features without an explicit // opt-in via `rustc_allow_const_fn_unstable`. - let attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id)); + let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id)); attr::rustc_allow_const_fn_unstable(tcx.sess, attrs).any(|name| name == feature_gate) }; diff --git a/compiler/rustc_passes/src/dead.rs b/compiler/rustc_passes/src/dead.rs index b4ebc2db3d60..7d1cc81e21f6 100644 --- a/compiler/rustc_passes/src/dead.rs +++ b/compiler/rustc_passes/src/dead.rs @@ -559,7 +559,7 @@ fn has_allow_dead_code_or_lang_attr( } fn has_allow_expect_dead_code(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let lint_level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; matches!(lint_level, lint::Allow | lint::Expect(_)) } @@ -805,10 +805,10 @@ impl<'tcx> DeadVisitor<'tcx> { }; let tcx = self.tcx; - let first_hir_id = tcx.hir().local_def_id_to_hir_id(first_id); + let first_hir_id = tcx.local_def_id_to_hir_id(first_id); let first_lint_level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, first_hir_id).0; assert!(dead_codes.iter().skip(1).all(|id| { - let hir_id = tcx.hir().local_def_id_to_hir_id(*id); + let hir_id = tcx.local_def_id_to_hir_id(*id); let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; level == first_lint_level })); @@ -969,7 +969,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { let def_id = item.id.owner_id.def_id; if !visitor.is_live_code(def_id) { let name = tcx.item_name(def_id.to_def_id()); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; dead_items.push(DeadItem { def_id, name, level }) @@ -997,7 +997,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { let def_id = variant.def_id.expect_local(); if !live_symbols.contains(&def_id) { // Record to group diagnostics. - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let level = tcx.lint_level_at_node(lint::builtin::DEAD_CODE, hir_id).0; dead_variants.push(DeadItem { def_id, name: variant.name, level }); continue; @@ -1009,7 +1009,7 @@ fn check_mod_deathness(tcx: TyCtxt<'_>, module: LocalModDefId) { .iter() .filter_map(|field| { let def_id = field.did.expect_local(); - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); if let ShouldWarnAboutField::Yes(is_pos) = visitor.should_warn_about_field(field) { diff --git a/compiler/rustc_passes/src/lang_items.rs b/compiler/rustc_passes/src/lang_items.rs index f78157f89ae3..23baf14aea1e 100644 --- a/compiler/rustc_passes/src/lang_items.rs +++ b/compiler/rustc_passes/src/lang_items.rs @@ -42,7 +42,7 @@ impl<'tcx> LanguageItemCollector<'tcx> { } fn check_for_lang(&mut self, actual_target: Target, def_id: LocalDefId) { - let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id)); + let attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); if let Some((name, span)) = extract(attrs) { match LangItem::from_name(name) { // Known lang item with attribute on correct target. diff --git a/compiler/rustc_passes/src/naked_functions.rs b/compiler/rustc_passes/src/naked_functions.rs index 54f296da5c53..bd73fa784422 100644 --- a/compiler/rustc_passes/src/naked_functions.rs +++ b/compiler/rustc_passes/src/naked_functions.rs @@ -68,7 +68,7 @@ fn check_inline(tcx: TyCtxt<'_>, def_id: LocalDefId) { /// Checks that function uses non-Rust ABI. fn check_abi(tcx: TyCtxt<'_>, def_id: LocalDefId, abi: Abi) { if abi == Abi::Rust { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); let span = tcx.def_span(def_id); tcx.emit_spanned_lint( UNDEFINED_NAKED_FUNCTION_ABI, diff --git a/compiler/rustc_passes/src/reachable.rs b/compiler/rustc_passes/src/reachable.rs index 650bb97c4d16..f89c1b0e47c6 100644 --- a/compiler/rustc_passes/src/reachable.rs +++ b/compiler/rustc_passes/src/reachable.rs @@ -260,9 +260,7 @@ impl<'tcx> ReachableContext<'tcx> { _ => { bug!( "found unexpected node kind in worklist: {} ({:?})", - self.tcx - .hir() - .node_to_string(self.tcx.hir().local_def_id_to_hir_id(search_item)), + self.tcx.hir().node_to_string(self.tcx.local_def_id_to_hir_id(search_item)), node, ); } diff --git a/compiler/rustc_passes/src/stability.rs b/compiler/rustc_passes/src/stability.rs index fd7cf1ac11e3..26bd52f55d4c 100644 --- a/compiler/rustc_passes/src/stability.rs +++ b/compiler/rustc_passes/src/stability.rs @@ -111,7 +111,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { ) where F: FnOnce(&mut Self), { - let attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id)); + let attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); debug!("annotate(id = {:?}, attrs = {:?})", def_id, attrs); let depr = attr::find_deprecation(self.tcx.sess, self.tcx.features(), attrs); @@ -120,7 +120,7 @@ impl<'a, 'tcx> Annotator<'a, 'tcx> { is_deprecated = true; if matches!(kind, AnnotationKind::Prohibited | AnnotationKind::DeprecationProhibited) { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = self.tcx.local_def_id_to_hir_id(def_id); self.tcx.emit_spanned_lint( USELESS_DEPRECATED, hir_id, diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 51d12ebdc088..b78c8b849f73 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -491,7 +491,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { macro_ev: EffectiveVisibility, ) { // Non-opaque macros cannot make other items more accessible than they already are. - let hir_id = self.tcx.hir().local_def_id_to_hir_id(local_def_id); + let hir_id = self.tcx.local_def_id_to_hir_id(local_def_id); let attrs = self.tcx.hir().attrs(hir_id); if attr::find_transparency(attrs, md.macro_rules).0 != Transparency::Opaque { return; @@ -1002,7 +1002,7 @@ impl<'tcx> NamePrivacyVisitor<'tcx> { // definition of the field let ident = Ident::new(kw::Empty, use_ctxt); - let hir_id = self.tcx.hir().local_def_id_to_hir_id(self.current_item); + let hir_id = self.tcx.local_def_id_to_hir_id(self.current_item); let def_id = self.tcx.adjust_ident_and_get_scope(ident, def.did(), hir_id).1; if !field.vis.is_accessible_from(def_id, self.tcx) { self.tcx.sess.emit_err(FieldIsPrivate { @@ -1440,7 +1440,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { if self.leaks_private_dep(def_id) { self.tcx.emit_spanned_lint( lint::builtin::EXPORTED_PRIVATE_DEPENDENCIES, - self.tcx.hir().local_def_id_to_hir_id(self.item_def_id), + self.tcx.local_def_id_to_hir_id(self.item_def_id), self.tcx.def_span(self.item_def_id.to_def_id()), FromPrivateDependencyInPublicInterface { kind, @@ -1497,7 +1497,7 @@ impl SearchInterfaceForPrivateItemsVisitor<'_> { }; self.tcx.emit_spanned_lint( lint, - self.tcx.hir().local_def_id_to_hir_id(self.item_def_id), + self.tcx.local_def_id_to_hir_id(self.item_def_id), span, PrivateInterfacesOrBoundsLint { item_span: span, @@ -1580,7 +1580,7 @@ impl<'tcx> PrivateItemsInPublicInterfacesChecker<'tcx, '_> { let reachable_at_vis = effective_vis.at_level(Level::Reachable); if reachable_at_vis.is_public() && reexported_at_vis != reachable_at_vis { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = self.tcx.local_def_id_to_hir_id(def_id); let span = self.tcx.def_span(def_id.to_def_id()); self.tcx.emit_spanned_lint( lint::builtin::UNNAMEABLE_TYPES, @@ -1820,7 +1820,7 @@ fn local_visibility(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::Visibility { match tcx.resolutions(()).visibilities.get(&def_id) { Some(vis) => *vis, None => { - let hir_id = tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = tcx.local_def_id_to_hir_id(def_id); match tcx.hir().get(hir_id) { // Unique types created for closures participate in type privacy checking. // They have visibilities inherited from the module they are defined in. diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs index 33e4fd33716f..feeeaa51f81d 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/on_unimplemented.rs @@ -393,7 +393,7 @@ impl IgnoredDiagnosticOption { if let (Some(new_item), Some(old_item)) = (new, old) { tcx.emit_spanned_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), new_item, IgnoredDiagnosticOption { span: new_item, prev_span: old_item, option_name }, ); @@ -511,7 +511,7 @@ impl<'tcx> OnUnimplementedDirective { if is_diagnostic_namespace_variant { tcx.emit_spanned_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), vec![item.span()], MalformedOnUnimplementedAttrLint::new(item.span()), ); @@ -651,7 +651,7 @@ impl<'tcx> OnUnimplementedDirective { tcx.emit_spanned_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), report_span, MalformedOnUnimplementedAttrLint::new(report_span), ); @@ -662,14 +662,14 @@ impl<'tcx> OnUnimplementedDirective { AttrKind::Normal(p) if !matches!(p.item.args, AttrArgs::Empty) => { tcx.emit_spanned_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), attr.span, MalformedOnUnimplementedAttrLint::new(attr.span), ); } _ => tcx.emit_spanned_lint( UNKNOWN_OR_MALFORMED_DIAGNOSTIC_ATTRIBUTES, - tcx.hir().local_def_id_to_hir_id(item_def_id.expect_local()), + tcx.local_def_id_to_hir_id(item_def_id.expect_local()), attr.span, MissingOptionsForOnUnimplementedAttr, ), diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs index f73e6f144df9..e4cb99727fc3 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/suggestions.rs @@ -871,7 +871,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { }; let hir = self.tcx.hir(); - let hir_id = hir.local_def_id_to_hir_id(def_id.as_local()?); + let hir_id = self.tcx.local_def_id_to_hir_id(def_id.as_local()?); match hir.find_parent(hir_id) { Some(hir::Node::Stmt(hir::Stmt { kind: hir::StmtKind::Local(local), .. })) => { get_name(err, &local.pat.kind) @@ -2414,7 +2414,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .tcx .parent(coroutine_did) .as_local() - .map(|parent_did| hir.local_def_id_to_hir_id(parent_did)) + .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did)) .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) .map(|name| { format!("future returned by `{name}` is not {trait_name}") @@ -2429,7 +2429,7 @@ impl<'tcx> TypeErrCtxtExt<'tcx> for TypeErrCtxt<'_, 'tcx> { .tcx .parent(coroutine_did) .as_local() - .map(|parent_did| hir.local_def_id_to_hir_id(parent_did)) + .map(|parent_did| self.tcx.local_def_id_to_hir_id(parent_did)) .and_then(|parent_hir_id| hir.opt_name(parent_hir_id)) .map(|name| { format!("iterator returned by `{name}` is not {trait_name}") diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs index 5718ab3b9664..b28bff1ca2a7 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/type_err_ctxt_ext.rs @@ -3075,7 +3075,7 @@ impl<'tcx> InferCtxtPrivExt<'tcx> for TypeErrCtxt<'_, 'tcx> { // Additional context information explaining why the closure only implements // a particular trait. if let Some(typeck_results) = &self.typeck_results { - let hir_id = self.tcx.hir().local_def_id_to_hir_id(closure_def_id.expect_local()); + let hir_id = self.tcx.local_def_id_to_hir_id(closure_def_id.expect_local()); match (found_kind, typeck_results.closure_kind_origins().get(hir_id)) { (ty::ClosureKind::FnOnce, Some((span, place))) => { err.fn_once_label = Some(ClosureFnOnceLabel { diff --git a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs index 0f7a0ab17ef1..eac633f1a9c4 100644 --- a/compiler/rustc_trait_selection/src/traits/specialize/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/specialize/mod.rs @@ -442,7 +442,7 @@ fn report_conflicting_impls<'tcx>( }; tcx.struct_span_lint_hir( lint, - tcx.hir().local_def_id_to_hir_id(impl_def_id), + tcx.local_def_id_to_hir_id(impl_def_id), impl_span, msg, |err| { diff --git a/compiler/rustc_ty_utils/src/assoc.rs b/compiler/rustc_ty_utils/src/assoc.rs index a1ebf386e74e..612123e79015 100644 --- a/compiler/rustc_ty_utils/src/assoc.rs +++ b/compiler/rustc_ty_utils/src/assoc.rs @@ -94,7 +94,7 @@ fn impl_item_implementor_ids(tcx: TyCtxt<'_>, impl_id: DefId) -> DefIdMap } fn associated_item(tcx: TyCtxt<'_>, def_id: LocalDefId) -> ty::AssocItem { - let id = tcx.hir().local_def_id_to_hir_id(def_id); + let id = tcx.local_def_id_to_hir_id(def_id); let parent_def_id = tcx.hir().get_parent_item(id); let parent_item = tcx.hir().expect_item(parent_def_id.def_id); match parent_item.kind { diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 7ca2da42042b..c17970e23a20 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -81,8 +81,8 @@ impl<'tcx> OpaqueTypeCollector<'tcx> { /// For the above example, this function returns `true` for `f1` and `false` for `f2`. #[instrument(level = "trace", skip(self), ret)] fn check_tait_defining_scope(&self, opaque_def_id: LocalDefId) -> bool { - let mut hir_id = self.tcx.hir().local_def_id_to_hir_id(self.item); - let opaque_hir_id = self.tcx.hir().local_def_id_to_hir_id(opaque_def_id); + let mut hir_id = self.tcx.local_def_id_to_hir_id(self.item); + let opaque_hir_id = self.tcx.local_def_id_to_hir_id(opaque_def_id); // Named opaque types can be defined by any siblings or children of siblings. let scope = self.tcx.hir().get_defining_scope(opaque_hir_id); diff --git a/src/librustdoc/clean/inline.rs b/src/librustdoc/clean/inline.rs index f7532185d711..014bcb1a8817 100644 --- a/src/librustdoc/clean/inline.rs +++ b/src/librustdoc/clean/inline.rs @@ -640,7 +640,7 @@ fn build_module_items( pub(crate) fn print_inlined_const(tcx: TyCtxt<'_>, did: DefId) -> String { if let Some(did) = did.as_local() { - let hir_id = tcx.hir().local_def_id_to_hir_id(did); + let hir_id = tcx.local_def_id_to_hir_id(did); rustc_hir_pretty::id_to_string(&tcx.hir(), hir_id) } else { tcx.rendered_const(did).clone() diff --git a/src/librustdoc/clean/types.rs b/src/librustdoc/clean/types.rs index ddbbce865488..f079d01bd842 100644 --- a/src/librustdoc/clean/types.rs +++ b/src/librustdoc/clean/types.rs @@ -345,7 +345,7 @@ pub(crate) fn rustc_span(def_id: DefId, tcx: TyCtxt<'_>) -> Span { || tcx.def_span(def_id), |local| { let hir = tcx.hir(); - hir.span_with_body(hir.local_def_id_to_hir_id(local)) + hir.span_with_body(tcx.local_def_id_to_hir_id(local)) }, )) } diff --git a/src/librustdoc/core.rs b/src/librustdoc/core.rs index 6d9f8b820c48..8215926ee331 100644 --- a/src/librustdoc/core.rs +++ b/src/librustdoc/core.rs @@ -107,12 +107,12 @@ impl<'tcx> DocContext<'tcx> { r } - /// Like `hir().local_def_id_to_hir_id()`, but skips calling it on fake DefIds. + /// Like `tcx.local_def_id_to_hir_id()`, but skips calling it on fake DefIds. /// (This avoids a slice-index-out-of-bounds panic.) pub(crate) fn as_local_hir_id(tcx: TyCtxt<'_>, item_id: ItemId) -> Option { match item_id { ItemId::DefId(real_id) => { - real_id.as_local().map(|def_id| tcx.hir().local_def_id_to_hir_id(def_id)) + real_id.as_local().map(|def_id| tcx.local_def_id_to_hir_id(def_id)) } // FIXME: Can this be `Some` for `Auto` or `Blanket`? _ => None, diff --git a/src/librustdoc/doctest.rs b/src/librustdoc/doctest.rs index 3a114bcc1856..172b72436278 100644 --- a/src/librustdoc/doctest.rs +++ b/src/librustdoc/doctest.rs @@ -1207,7 +1207,7 @@ impl<'a, 'hir, 'tcx> HirCollector<'a, 'hir, 'tcx> { sp: Span, nested: F, ) { - let ast_attrs = self.tcx.hir().attrs(self.tcx.hir().local_def_id_to_hir_id(def_id)); + let ast_attrs = self.tcx.hir().attrs(self.tcx.local_def_id_to_hir_id(def_id)); if let Some(ref cfg) = ast_attrs.cfg(self.tcx, &FxHashSet::default()) { if !cfg.matches(&self.sess.parse_sess, Some(self.tcx.features())) { return; diff --git a/src/librustdoc/html/markdown.rs b/src/librustdoc/html/markdown.rs index 39d7e120df9d..abc27bcdf078 100644 --- a/src/librustdoc/html/markdown.rs +++ b/src/librustdoc/html/markdown.rs @@ -841,7 +841,7 @@ impl<'tcx> ExtraInfo<'tcx> { if let Some(def_id) = self.def_id.as_local() { self.tcx.struct_span_lint_hir( crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, - self.tcx.hir().local_def_id_to_hir_id(def_id), + self.tcx.local_def_id_to_hir_id(def_id), self.sp, msg, |l| l, @@ -857,7 +857,7 @@ impl<'tcx> ExtraInfo<'tcx> { if let Some(def_id) = self.def_id.as_local() { self.tcx.struct_span_lint_hir( crate::lint::INVALID_CODEBLOCK_ATTRIBUTES, - self.tcx.hir().local_def_id_to_hir_id(def_id), + self.tcx.local_def_id_to_hir_id(def_id), self.sp, msg, |lint| lint.help(help), diff --git a/src/librustdoc/passes/check_doc_test_visibility.rs b/src/librustdoc/passes/check_doc_test_visibility.rs index a5f4972d4091..21a31b9df930 100644 --- a/src/librustdoc/passes/check_doc_test_visibility.rs +++ b/src/librustdoc/passes/check_doc_test_visibility.rs @@ -100,7 +100,7 @@ pub(crate) fn should_have_doc_example(cx: &DocContext<'_>, item: &clean::Item) - } let (level, source) = cx.tcx.lint_level_at_node( crate::lint::MISSING_DOC_CODE_EXAMPLES, - cx.tcx.hir().local_def_id_to_hir_id(def_id), + cx.tcx.local_def_id_to_hir_id(def_id), ); level != lint::Level::Allow || matches!(source, LintLevelSource::Default) } diff --git a/src/librustdoc/passes/lint/check_code_block_syntax.rs b/src/librustdoc/passes/lint/check_code_block_syntax.rs index ac8a75a4f18c..e9b9e36a5303 100644 --- a/src/librustdoc/passes/lint/check_code_block_syntax.rs +++ b/src/librustdoc/passes/lint/check_code_block_syntax.rs @@ -98,7 +98,7 @@ fn check_rust_syntax( // Finally build and emit the completed diagnostic. // All points of divergence have been handled earlier so this can be // done the same way whether the span is precise or not. - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(local_id); cx.tcx.struct_span_lint_hir(crate::lint::INVALID_RUST_CODEBLOCKS, hir_id, sp, msg, |lint| { let explanation = if is_ignore { "`ignore` code blocks require valid Rust code for syntax highlighting; \ diff --git a/src/librustdoc/visit_ast.rs b/src/librustdoc/visit_ast.rs index d84a137987cb..bef151745d8f 100644 --- a/src/librustdoc/visit_ast.rs +++ b/src/librustdoc/visit_ast.rs @@ -242,7 +242,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { }; let document_hidden = self.cx.render_options.document_hidden; - let use_attrs = tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(def_id)); + let use_attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(def_id)); // Don't inline `doc(hidden)` imports so they can be stripped at a later stage. let is_no_inline = use_attrs.lists(sym::doc).has_word(sym::no_inline) || (document_hidden && use_attrs.lists(sym::doc).has_word(sym::hidden)); @@ -446,8 +446,7 @@ impl<'a, 'tcx> RustdocVisitor<'a, 'tcx> { continue; } - let attrs = - tcx.hir().attrs(tcx.hir().local_def_id_to_hir_id(item.owner_id.def_id)); + let attrs = tcx.hir().attrs(tcx.local_def_id_to_hir_id(item.owner_id.def_id)); // If there was a private module in the current path then don't bother inlining // anything as it will probably be stripped anyway. diff --git a/src/tools/clippy/clippy_lints/src/derive.rs b/src/tools/clippy/clippy_lints/src/derive.rs index 169c2a15db71..64573ac4d53d 100644 --- a/src/tools/clippy/clippy_lints/src/derive.rs +++ b/src/tools/clippy/clippy_lints/src/derive.rs @@ -255,7 +255,7 @@ fn check_hash_peq<'tcx>( "you are deriving `Hash` but have implemented `PartialEq` explicitly", |diag| { if let Some(local_def_id) = impl_id.as_local() { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); diag.span_note(cx.tcx.hir().span(hir_id), "`PartialEq` implemented here"); } }, @@ -299,7 +299,7 @@ fn check_ord_partial_ord<'tcx>( span_lint_and_then(cx, DERIVE_ORD_XOR_PARTIAL_ORD, span, mess, |diag| { if let Some(local_def_id) = impl_id.as_local() { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id); diag.span_note(cx.tcx.hir().span(hir_id), "`PartialOrd` implemented here"); } }); @@ -381,7 +381,7 @@ fn check_unsafe_derive_deserialize<'tcx>( && match_def_path(cx, trait_def_id, &paths::SERDE_DESERIALIZE) && let ty::Adt(def, _) = ty.kind() && let Some(local_def_id) = def.did().as_local() - && let adt_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_def_id) + && let adt_hir_id = cx.tcx.local_def_id_to_hir_id(local_def_id) && !is_lint_allowed(cx, UNSAFE_DERIVE_DESERIALIZE, adt_hir_id) && cx .tcx diff --git a/src/tools/clippy/clippy_lints/src/error_impl_error.rs b/src/tools/clippy/clippy_lints/src/error_impl_error.rs index bc878555c66d..35b1d3f9bab0 100644 --- a/src/tools/clippy/clippy_lints/src/error_impl_error.rs +++ b/src/tools/clippy/clippy_lints/src/error_impl_error.rs @@ -58,7 +58,7 @@ impl<'tcx> LateLintPass<'tcx> for ErrorImplError { if let Some(trait_def_id) = imp.of_trait.and_then(|t| t.trait_def_id()) && error_def_id == trait_def_id && let Some(def_id) = path_res(cx, imp.self_ty).opt_def_id().and_then(DefId::as_local) - && let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id) + && let hir_id = cx.tcx.local_def_id_to_hir_id(def_id) && let Some(ident) = cx.tcx.opt_item_ident(def_id.to_def_id()) && ident.name == sym::Error && is_visible_outside_module(cx, def_id) => diff --git a/src/tools/clippy/clippy_lints/src/escape.rs b/src/tools/clippy/clippy_lints/src/escape.rs index 2f22f344a21b..af2d1c27d433 100644 --- a/src/tools/clippy/clippy_lints/src/escape.rs +++ b/src/tools/clippy/clippy_lints/src/escape.rs @@ -74,7 +74,7 @@ impl<'tcx> LateLintPass<'tcx> for BoxedLocal { let parent_id = cx .tcx .hir() - .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(fn_def_id)) + .get_parent_item(cx.tcx.local_def_id_to_hir_id(fn_def_id)) .def_id; let parent_node = cx.tcx.hir().find_by_def_id(parent_id); diff --git a/src/tools/clippy/clippy_lints/src/excessive_bools.rs b/src/tools/clippy/clippy_lints/src/excessive_bools.rs index 1d18e194d15c..713957bff51a 100644 --- a/src/tools/clippy/clippy_lints/src/excessive_bools.rs +++ b/src/tools/clippy/clippy_lints/src/excessive_bools.rs @@ -171,7 +171,7 @@ impl<'tcx> LateLintPass<'tcx> for ExcessiveBools { span: Span, def_id: LocalDefId, ) { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); if let Some(fn_header) = fn_kind.header() && fn_header.abi == Abi::Rust && get_parent_as_impl(cx.tcx, hir_id).map_or(true, |impl_item| impl_item.of_trait.is_none()) diff --git a/src/tools/clippy/clippy_lints/src/functions/mod.rs b/src/tools/clippy/clippy_lints/src/functions/mod.rs index 3f5cceec70ed..bfd73debd76f 100644 --- a/src/tools/clippy/clippy_lints/src/functions/mod.rs +++ b/src/tools/clippy/clippy_lints/src/functions/mod.rs @@ -407,7 +407,7 @@ impl<'tcx> LateLintPass<'tcx> for Functions { span: Span, def_id: LocalDefId, ) { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); too_many_arguments::check_fn(cx, kind, decl, span, hir_id, self.too_many_arguments_threshold); too_many_lines::check_fn(cx, kind, span, body, self.too_many_lines_threshold); not_unsafe_ptr_arg_deref::check_fn(cx, kind, decl, body, def_id); diff --git a/src/tools/clippy/clippy_lints/src/future_not_send.rs b/src/tools/clippy/clippy_lints/src/future_not_send.rs index eee5b7540ba7..ded90f5f9110 100644 --- a/src/tools/clippy/clippy_lints/src/future_not_send.rs +++ b/src/tools/clippy/clippy_lints/src/future_not_send.rs @@ -62,7 +62,7 @@ impl<'tcx> LateLintPass<'tcx> for FutureNotSend { if let FnKind::Closure = kind { return; } - let ret_ty = return_ty(cx, cx.tcx.hir().local_def_id_to_hir_id(fn_def_id).expect_owner()); + let ret_ty = return_ty(cx, cx.tcx.local_def_id_to_hir_id(fn_def_id).expect_owner()); if let ty::Alias(ty::Opaque, AliasTy { def_id, args, .. }) = *ret_ty.kind() { let preds = cx.tcx.explicit_item_bounds(def_id); let mut is_future = false; diff --git a/src/tools/clippy/clippy_lints/src/inherent_impl.rs b/src/tools/clippy/clippy_lints/src/inherent_impl.rs index a61a64161930..aa732980b1ff 100644 --- a/src/tools/clippy/clippy_lints/src/inherent_impl.rs +++ b/src/tools/clippy/clippy_lints/src/inherent_impl.rs @@ -63,7 +63,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { && !is_lint_allowed( cx, MULTIPLE_INHERENT_IMPL, - cx.tcx.hir().local_def_id_to_hir_id(id), + cx.tcx.local_def_id_to_hir_id(id), ) }) { for impl_id in impl_ids.iter().map(|id| id.expect_local()) { @@ -117,7 +117,7 @@ impl<'tcx> LateLintPass<'tcx> for MultipleInherentImpl { /// Gets the span for the given impl block unless it's not being considered by the lint. fn get_impl_span(cx: &LateContext<'_>, id: LocalDefId) -> Option { - let id = cx.tcx.hir().local_def_id_to_hir_id(id); + let id = cx.tcx.local_def_id_to_hir_id(id); if let Node::Item(&Item { kind: ItemKind::Impl(impl_item), span, diff --git a/src/tools/clippy/clippy_lints/src/len_zero.rs b/src/tools/clippy/clippy_lints/src/len_zero.rs index 6fc14dd89417..8c6ef81ccedf 100644 --- a/src/tools/clippy/clippy_lints/src/len_zero.rs +++ b/src/tools/clippy/clippy_lints/src/len_zero.rs @@ -142,7 +142,7 @@ impl<'tcx> LateLintPass<'tcx> for LenZero { && let TyKind::Path(ty_path) = &imp.self_ty.kind && let Some(ty_id) = cx.qpath_res(ty_path, imp.self_ty.hir_id).opt_def_id() && let Some(local_id) = ty_id.as_local() - && let ty_hir_id = cx.tcx.hir().local_def_id_to_hir_id(local_id) + && let ty_hir_id = cx.tcx.local_def_id_to_hir_id(local_id) && !is_lint_allowed(cx, LEN_WITHOUT_IS_EMPTY, ty_hir_id) && let Some(output) = parse_len_output(cx, cx.tcx.fn_sig(item.owner_id).instantiate_identity().skip_binder()) diff --git a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs index fc8f23630013..79cc98bfb7fa 100644 --- a/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs +++ b/src/tools/clippy/clippy_lints/src/manual_non_exhaustive.rs @@ -192,7 +192,7 @@ impl<'tcx> LateLintPass<'tcx> for ManualNonExhaustiveEnum { .contains(&(enum_id.to_def_id(), variant_id.to_def_id())) }) { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(enum_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(enum_id); span_lint_hir_and_then( cx, MANUAL_NON_EXHAUSTIVE, diff --git a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs index 9950c4428551..2e43d19a6991 100644 --- a/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs +++ b/src/tools/clippy/clippy_lints/src/methods/filter_map_bool_then.rs @@ -27,7 +27,7 @@ pub(super) fn check<'tcx>(cx: &LateContext<'tcx>, expr: &'tcx Expr<'tcx>, arg: & closure.def_id.to_def_id(), Binder::bind_with_vars( cx.typeck_results().node_type(param_ty.hir_id), - cx.tcx.late_bound_vars(cx.tcx.hir().local_def_id_to_hir_id(closure.def_id)), + cx.tcx.late_bound_vars(cx.tcx.local_def_id_to_hir_id(closure.def_id)), ), ) && is_copy(cx, param_ty) diff --git a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs index 97522cbe6cea..496bae583f10 100644 --- a/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs +++ b/src/tools/clippy/clippy_lints/src/missing_const_for_fn.rs @@ -131,7 +131,7 @@ impl<'tcx> LateLintPass<'tcx> for MissingConstForFn { FnKind::Closure => return, } - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); // Const fns are not allowed as methods in a trait. { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs index d610ba520a48..f4ccd26631f1 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_ref_mut.rs @@ -137,7 +137,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { return; } - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def_id); let is_async = match kind { FnKind::ItemFn(.., header) => { if header.is_unsafe() { @@ -256,7 +256,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByRefMut<'tcx> { span_lint_hir_and_then( cx, NEEDLESS_PASS_BY_REF_MUT, - cx.tcx.hir().local_def_id_to_hir_id(*fn_def_id), + cx.tcx.local_def_id_to_hir_id(*fn_def_id), sp, "this argument is a mutable reference, but not used mutably", |diag| { diff --git a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs index 7c48b84e4306..5442463bbf58 100644 --- a/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs +++ b/src/tools/clippy/clippy_lints/src/needless_pass_by_value.rs @@ -86,7 +86,7 @@ impl<'tcx> LateLintPass<'tcx> for NeedlessPassByValue { return; } - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def_id); match kind { FnKind::ItemFn(.., header) => { diff --git a/src/tools/clippy/clippy_lints/src/new_without_default.rs b/src/tools/clippy/clippy_lints/src/new_without_default.rs index abba622a285a..2f6aebae4f50 100644 --- a/src/tools/clippy/clippy_lints/src/new_without_default.rs +++ b/src/tools/clippy/clippy_lints/src/new_without_default.rs @@ -106,7 +106,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { let ty = cx.tcx.type_of(d).instantiate_identity(); if let Some(ty_def) = ty.ty_adt_def() { if let Some(local_def_id) = ty_def.did().as_local() { - impls.insert(cx.tcx.hir().local_def_id_to_hir_id(local_def_id)); + impls.insert(cx.tcx.local_def_id_to_hir_id(local_def_id)); } } }); @@ -119,7 +119,7 @@ impl<'tcx> LateLintPass<'tcx> for NewWithoutDefault { && let self_def = cx.tcx.type_of(self_def_id).instantiate_identity() && let Some(self_def) = self_def.ty_adt_def() && let Some(self_local_did) = self_def.did().as_local() - && let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did) + && let self_id = cx.tcx.local_def_id_to_hir_id(self_local_did) && impling_types.contains(&self_id) { return; diff --git a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs index df1476e68098..d07a9da55a22 100644 --- a/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs +++ b/src/tools/clippy/clippy_lints/src/non_send_fields_in_send_ty.rs @@ -100,7 +100,7 @@ impl<'tcx> LateLintPass<'tcx> for NonSendFieldInSendTy { if let Some(field_hir_id) = field .did .as_local() - .map(|local_def_id| hir_map.local_def_id_to_hir_id(local_def_id)) + .map(|local_def_id| cx.tcx.local_def_id_to_hir_id(local_def_id)) && !is_lint_allowed(cx, NON_SEND_FIELDS_IN_SEND_TY, field_hir_id) && let field_ty = field.ty(cx.tcx, impl_trait_args) && !ty_allowed_in_send(cx, field_ty, send_trait) diff --git a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs index 6a760f9fe64a..f4dc80d744a0 100644 --- a/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs +++ b/src/tools/clippy/clippy_lints/src/panic_in_result_fn.rs @@ -55,7 +55,7 @@ impl<'tcx> LateLintPass<'tcx> for PanicInResultFn { if matches!(fn_kind, FnKind::Closure) { return; } - let owner = cx.tcx.hir().local_def_id_to_hir_id(def_id).expect_owner(); + let owner = cx.tcx.local_def_id_to_hir_id(def_id).expect_owner(); if is_type_diagnostic_item(cx, return_ty(cx, owner), sym::Result) { lint_impl_body(cx, span, body); } diff --git a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs index bbca8a123e68..98d284d03403 100644 --- a/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs +++ b/src/tools/clippy/clippy_lints/src/pass_by_ref_or_value.rs @@ -279,7 +279,7 @@ impl<'tcx> LateLintPass<'tcx> for PassByRefOrValue { return; } - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); match kind { FnKind::ItemFn(.., header) => { if header.abi != Abi::Rust { diff --git a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs index ad22b751befa..1a23757f7d6e 100644 --- a/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs +++ b/src/tools/clippy/clippy_lints/src/return_self_not_must_use.rs @@ -115,7 +115,7 @@ impl<'tcx> LateLintPass<'tcx> for ReturnSelfNotMustUse { // `#[must_use]` should be put on the trait definition directly. && cx.tcx.trait_id_of_impl(impl_def).is_none() { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(fn_def); + let hir_id = cx.tcx.local_def_id_to_hir_id(fn_def); check_method(cx, decl, fn_def, span, hir_id.expect_owner()); } } diff --git a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs index c1edcf509efa..36cb2edf7237 100644 --- a/src/tools/clippy/clippy_lints/src/self_named_constructors.rs +++ b/src/tools/clippy/clippy_lints/src/self_named_constructors.rs @@ -72,7 +72,7 @@ impl<'tcx> LateLintPass<'tcx> for SelfNamedConstructors { if let Some(self_def) = self_ty.ty_adt_def() && let Some(self_local_did) = self_def.did().as_local() - && let self_id = cx.tcx.hir().local_def_id_to_hir_id(self_local_did) + && let self_id = cx.tcx.local_def_id_to_hir_id(self_local_did) && let Some(Node::Item(x)) = cx.tcx.hir().find(self_id) && let type_name = x.ident.name.as_str().to_lowercase() && (impl_item.ident.name.as_str() == type_name diff --git a/src/tools/clippy/clippy_lints/src/types/mod.rs b/src/tools/clippy/clippy_lints/src/types/mod.rs index f333b2cdcb49..4037808d34f1 100644 --- a/src/tools/clippy/clippy_lints/src/types/mod.rs +++ b/src/tools/clippy/clippy_lints/src/types/mod.rs @@ -324,7 +324,7 @@ impl<'tcx> LateLintPass<'tcx> for Types { let is_in_trait_impl = if let Some(hir::Node::Item(item)) = cx.tcx.hir().find_by_def_id( cx.tcx .hir() - .get_parent_item(cx.tcx.hir().local_def_id_to_hir_id(def_id)) + .get_parent_item(cx.tcx.local_def_id_to_hir_id(def_id)) .def_id, ) { matches!(item.kind, ItemKind::Impl(hir::Impl { of_trait: Some(_), .. })) diff --git a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs index 32aebdd8c0f7..41c4d3359f4b 100644 --- a/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs +++ b/src/tools/clippy/clippy_lints/src/undocumented_unsafe_blocks.rs @@ -349,7 +349,7 @@ fn block_parents_have_safety_comment( span, owner_id, .. - })) => (*span, cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id)), + })) => (*span, cx.tcx.local_def_id_to_hir_id(owner_id.def_id)), _ => { if is_branchy(expr) { return false; @@ -370,7 +370,7 @@ fn block_parents_have_safety_comment( span, owner_id, .. - }) => (*span, cx.tcx.hir().local_def_id_to_hir_id(owner_id.def_id)), + }) => (*span, cx.tcx.local_def_id_to_hir_id(owner_id.def_id)), _ => return false, }; // if unsafe block is part of a let/const/static statement, diff --git a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs index 5599a9dc4e81..0d551639ea9f 100644 --- a/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs +++ b/src/tools/clippy/clippy_lints/src/unnecessary_wraps.rs @@ -91,7 +91,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryWraps { } // Abort if the method is implementing a trait or of it a trait method. - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); if let Some(Node::Item(item)) = cx.tcx.hir().find_parent(hir_id) { if matches!( item.kind, diff --git a/src/tools/clippy/clippy_utils/src/lib.rs b/src/tools/clippy/clippy_utils/src/lib.rs index 2466e8bb339d..172b063df315 100644 --- a/src/tools/clippy/clippy_utils/src/lib.rs +++ b/src/tools/clippy/clippy_utils/src/lib.rs @@ -709,7 +709,7 @@ pub fn get_trait_def_id(cx: &LateContext<'_>, path: &[&str]) -> Option { /// ``` pub fn trait_ref_of_method<'tcx>(cx: &LateContext<'tcx>, def_id: LocalDefId) -> Option<&'tcx TraitRef<'tcx>> { // Get the implemented trait for the current function - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(def_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(def_id); let parent_impl = cx.tcx.hir().get_parent_item(hir_id); if parent_impl != hir::CRATE_OWNER_ID && let hir::Node::Item(item) = cx.tcx.hir().get_by_def_id(parent_impl.def_id) @@ -2567,7 +2567,7 @@ pub fn inherits_cfg(tcx: TyCtxt<'_>, def_id: LocalDefId) -> bool { tcx.has_attr(def_id, sym::cfg) || hir - .parent_iter(hir.local_def_id_to_hir_id(def_id)) + .parent_iter(tcx.local_def_id_to_hir_id(def_id)) .flat_map(|(parent_id, _)| hir.attrs(parent_id)) .any(|attr| attr.has_name(sym::cfg)) } @@ -2687,7 +2687,7 @@ impl<'tcx> ExprUseNode<'tcx> { .and(Binder::dummy(cx.tcx.type_of(id).instantiate_identity())), )), Self::Return(id) => { - let hir_id = cx.tcx.hir().local_def_id_to_hir_id(id.def_id); + let hir_id = cx.tcx.local_def_id_to_hir_id(id.def_id); if let Some(Node::Expr(Expr { kind: ExprKind::Closure(c), .. diff --git a/src/tools/clippy/clippy_utils/src/ty.rs b/src/tools/clippy/clippy_utils/src/ty.rs index 20588b63a78d..1e748a46922c 100644 --- a/src/tools/clippy/clippy_utils/src/ty.rs +++ b/src/tools/clippy/clippy_utils/src/ty.rs @@ -694,7 +694,7 @@ pub fn ty_sig<'tcx>(cx: &LateContext<'tcx>, ty: Ty<'tcx>) -> Option { let decl = id .as_local() - .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.hir().local_def_id_to_hir_id(id))); + .and_then(|id| cx.tcx.hir().fn_decl_by_hir_id(cx.tcx.local_def_id_to_hir_id(id))); Some(ExprFnSig::Closure(decl, subs.as_closure().sig())) }, ty::FnDef(id, subs) => Some(ExprFnSig::Sig(cx.tcx.fn_sig(id).instantiate(cx.tcx, subs), Some(id))), diff --git a/src/tools/miri/src/bin/miri.rs b/src/tools/miri/src/bin/miri.rs index 4517de628931..5cdeedafe95a 100644 --- a/src/tools/miri/src/bin/miri.rs +++ b/src/tools/miri/src/bin/miri.rs @@ -144,7 +144,7 @@ impl rustc_driver::Callbacks for MiriBeRustCompilerCalls { // Otherwise it may cause unexpected behaviours and ICEs // (https://github.com/rust-lang/rust/issues/86261). let is_reachable_non_generic = matches!( - tcx.hir().get(tcx.hir().local_def_id_to_hir_id(local_def_id)), + tcx.hir().get(tcx.local_def_id_to_hir_id(local_def_id)), Node::Item(&hir::Item { kind: hir::ItemKind::Static(..) | hir::ItemKind::Fn(..), .. From f23befe6c118573a2ca041bc89f959a8813b43a2 Mon Sep 17 00:00:00 2001 From: bohan Date: Sun, 26 Nov 2023 21:05:08 +0800 Subject: [PATCH 84/93] merge `DefKind::Coroutine` into `DefKind::Closure` --- compiler/rustc_ast_lowering/src/index.rs | 2 +- .../src/diagnostics/conflict_errors.rs | 9 +++++- compiler/rustc_borrowck/src/type_check/mod.rs | 4 ++- .../src/coverageinfo/mapgen.rs | 5 +-- compiler/rustc_hir/src/def.rs | 6 +--- .../rustc_hir_analysis/src/check/check.rs | 4 +-- compiler/rustc_interface/src/passes.rs | 2 +- compiler/rustc_metadata/src/rmeta/encoder.rs | 32 +++++++------------ compiler/rustc_metadata/src/rmeta/table.rs | 1 - compiler/rustc_middle/src/hir/map/mod.rs | 5 ++- compiler/rustc_middle/src/ty/context.rs | 4 +++ compiler/rustc_middle/src/ty/util.rs | 31 +++++++++--------- compiler/rustc_mir_build/src/build/mod.rs | 16 +++++----- compiler/rustc_mir_build/src/thir/cx/mod.rs | 24 +++++++------- .../rustc_mir_transform/src/const_prop.rs | 3 +- .../src/const_prop_lint.rs | 2 +- compiler/rustc_mir_transform/src/lib.rs | 2 +- .../rustc_monomorphize/src/polymorphize.rs | 4 +-- compiler/rustc_privacy/src/lib.rs | 3 +- .../rustc_resolve/src/build_reduced_graph.rs | 3 +- compiler/rustc_smir/src/rustc_smir/mod.rs | 2 +- compiler/rustc_symbol_mangling/src/lib.rs | 2 +- compiler/rustc_ty_utils/src/implied_bounds.rs | 3 +- compiler/rustc_ty_utils/src/opaque_types.rs | 2 +- compiler/rustc_ty_utils/src/sig_types.rs | 2 +- src/librustdoc/formats/item_type.rs | 3 +- .../passes/collect_intra_doc_links.rs | 1 - 27 files changed, 83 insertions(+), 94 deletions(-) diff --git a/compiler/rustc_ast_lowering/src/index.rs b/compiler/rustc_ast_lowering/src/index.rs index 33e15d386c88..e91b78720a86 100644 --- a/compiler/rustc_ast_lowering/src/index.rs +++ b/compiler/rustc_ast_lowering/src/index.rs @@ -89,7 +89,7 @@ impl<'a, 'hir> NodeCollector<'a, 'hir> { } } - self.nodes.insert(hir_id.local_id, ParentedNode { parent: self.parent_node, node: node }); + self.nodes.insert(hir_id.local_id, ParentedNode { parent: self.parent_node, node }); } fn with_parent(&mut self, parent_node_id: HirId, f: F) { diff --git a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs index 6d4c46553c9a..46ad67a2e3a1 100644 --- a/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/conflict_errors.rs @@ -2072,8 +2072,15 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { .map(|name| format!("function `{name}`")) .unwrap_or_else(|| { match &self.infcx.tcx.def_kind(self.mir_def_id()) { + DefKind::Closure + if self + .infcx + .tcx + .is_coroutine(self.mir_def_id().to_def_id()) => + { + "enclosing coroutine" + } DefKind::Closure => "enclosing closure", - DefKind::Coroutine => "enclosing coroutine", kind => bug!("expected closure or coroutine, found {:?}", kind), } .to_string() diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index dff86f6343d4..240a67ea1b29 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -2678,8 +2678,10 @@ impl<'a, 'tcx> TypeChecker<'a, 'tcx> { let typeck_root_args = ty::GenericArgs::identity_for_item(tcx, typeck_root_def_id); let parent_args = match tcx.def_kind(def_id) { + DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => { + args.as_coroutine().parent_args() + } DefKind::Closure => args.as_closure().parent_args(), - DefKind::Coroutine => args.as_coroutine().parent_args(), DefKind::InlineConst => args.as_inline_const().parent_args(), other => bug!("unexpected item {:?}", other), }; diff --git a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs index f2be6f27ff6f..51df14df644e 100644 --- a/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs +++ b/compiler/rustc_codegen_llvm/src/coverageinfo/mapgen.rs @@ -373,10 +373,7 @@ fn add_unused_functions(cx: &CodegenCx<'_, '_>) { // just "functions", like consts, statics, etc. Filter those out. // If `ignore_unused_generics` was specified, filter out any // generic functions from consideration as well. - if !matches!( - kind, - DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Coroutine - ) { + if !matches!(kind, DefKind::Fn | DefKind::AssocFn | DefKind::Closure) { return None; } if ignore_unused_generics && tcx.generics_of(def_id).requires_monomorphization(tcx) { diff --git a/compiler/rustc_hir/src/def.rs b/compiler/rustc_hir/src/def.rs index e901eba35b78..fedd380cada3 100644 --- a/compiler/rustc_hir/src/def.rs +++ b/compiler/rustc_hir/src/def.rs @@ -114,7 +114,6 @@ pub enum DefKind { of_trait: bool, }, Closure, - Coroutine, } impl DefKind { @@ -157,7 +156,6 @@ impl DefKind { DefKind::Field => "field", DefKind::Impl { .. } => "implementation", DefKind::Closure => "closure", - DefKind::Coroutine => "coroutine", DefKind::ExternCrate => "extern crate", DefKind::GlobalAsm => "global assembly block", } @@ -216,7 +214,6 @@ impl DefKind { | DefKind::LifetimeParam | DefKind::ExternCrate | DefKind::Closure - | DefKind::Coroutine | DefKind::Use | DefKind::ForeignMod | DefKind::GlobalAsm @@ -226,7 +223,7 @@ impl DefKind { #[inline] pub fn is_fn_like(self) -> bool { - matches!(self, DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Coroutine) + matches!(self, DefKind::Fn | DefKind::AssocFn | DefKind::Closure) } /// Whether `query get_codegen_attrs` should be used with this definition. @@ -236,7 +233,6 @@ impl DefKind { | DefKind::AssocFn | DefKind::Ctor(..) | DefKind::Closure - | DefKind::Coroutine | DefKind::Static(_) => true, DefKind::Mod | DefKind::Struct diff --git a/compiler/rustc_hir_analysis/src/check/check.rs b/compiler/rustc_hir_analysis/src/check/check.rs index 00f636862beb..6ab5f1f512f2 100644 --- a/compiler/rustc_hir_analysis/src/check/check.rs +++ b/compiler/rustc_hir_analysis/src/check/check.rs @@ -1451,7 +1451,7 @@ fn opaque_type_cycle_error( label_match(capture.place.ty(), capture.get_path_span(tcx)); } // Label any coroutine locals that capture the opaque - if let DefKind::Coroutine = tcx.def_kind(closure_def_id) + if tcx.is_coroutine(closure_def_id) && let Some(coroutine_layout) = tcx.mir_coroutine_witnesses(closure_def_id) { for interior_ty in &coroutine_layout.field_tys { @@ -1472,7 +1472,7 @@ pub(super) fn check_coroutine_obligations( tcx: TyCtxt<'_>, def_id: LocalDefId, ) -> Result<(), ErrorGuaranteed> { - debug_assert!(matches!(tcx.def_kind(def_id), DefKind::Coroutine)); + debug_assert!(tcx.is_coroutine(def_id.to_def_id())); let typeck = tcx.typeck(def_id); let param_env = tcx.param_env(def_id); diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 99bea647bd5e..4648d83a6f30 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -756,7 +756,7 @@ fn analysis(tcx: TyCtxt<'_>, (): ()) -> Result<()> { }); tcx.hir().par_body_owners(|def_id| { - if let rustc_hir::def::DefKind::Coroutine = tcx.def_kind(def_id) { + if tcx.is_coroutine(def_id.to_def_id()) { tcx.ensure().mir_coroutine_witnesses(def_id); tcx.ensure().check_coroutine_obligations(def_id); } diff --git a/compiler/rustc_metadata/src/rmeta/encoder.rs b/compiler/rustc_metadata/src/rmeta/encoder.rs index 562eaf213d22..c5953095d56e 100644 --- a/compiler/rustc_metadata/src/rmeta/encoder.rs +++ b/compiler/rustc_metadata/src/rmeta/encoder.rs @@ -856,8 +856,7 @@ fn should_encode_span(def_kind: DefKind) -> bool { | DefKind::OpaqueTy | DefKind::Field | DefKind::Impl { .. } - | DefKind::Closure - | DefKind::Coroutine => true, + | DefKind::Closure => true, DefKind::ForeignMod | DefKind::GlobalAsm => false, } } @@ -897,8 +896,7 @@ fn should_encode_attrs(def_kind: DefKind) -> bool { | DefKind::InlineConst | DefKind::OpaqueTy | DefKind::LifetimeParam - | DefKind::GlobalAsm - | DefKind::Coroutine => false, + | DefKind::GlobalAsm => false, } } @@ -933,8 +931,7 @@ fn should_encode_expn_that_defined(def_kind: DefKind) -> bool { | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm - | DefKind::Closure - | DefKind::Coroutine => false, + | DefKind::Closure => false, } } @@ -969,7 +966,6 @@ fn should_encode_visibility(def_kind: DefKind) -> bool { | DefKind::GlobalAsm | DefKind::Impl { .. } | DefKind::Closure - | DefKind::Coroutine | DefKind::ExternCrate => false, } } @@ -1005,7 +1001,6 @@ fn should_encode_stability(def_kind: DefKind) -> bool { | DefKind::InlineConst | DefKind::GlobalAsm | DefKind::Closure - | DefKind::Coroutine | DefKind::ExternCrate => false, } } @@ -1048,6 +1043,8 @@ fn should_encode_mir( | DefKind::AssocConst | DefKind::Static(..) | DefKind::Const => (true, false), + // Coroutines require optimized MIR to compute layout. + DefKind::Closure if tcx.is_coroutine(def_id.to_def_id()) => (false, true), // Full-fledged functions + closures DefKind::AssocFn | DefKind::Fn | DefKind::Closure => { let generics = tcx.generics_of(def_id); @@ -1061,8 +1058,6 @@ fn should_encode_mir( || tcx.is_const_default_method(def_id.to_def_id()); (is_const_fn, opt) } - // Coroutines require optimized MIR to compute layout. - DefKind::Coroutine => (false, true), // The others don't have MIR. _ => (false, false), } @@ -1098,7 +1093,6 @@ fn should_encode_variances<'tcx>(tcx: TyCtxt<'tcx>, def_id: DefId, def_kind: Def | DefKind::InlineConst | DefKind::GlobalAsm | DefKind::Closure - | DefKind::Coroutine | DefKind::ExternCrate => false, DefKind::TyAlias => tcx.type_alias_is_lazy(def_id), } @@ -1127,8 +1121,7 @@ fn should_encode_generics(def_kind: DefKind) -> bool { | DefKind::Impl { .. } | DefKind::Field | DefKind::TyParam - | DefKind::Closure - | DefKind::Coroutine => true, + | DefKind::Closure => true, DefKind::Mod | DefKind::ForeignMod | DefKind::ConstParam @@ -1157,7 +1150,6 @@ fn should_encode_type(tcx: TyCtxt<'_>, def_id: LocalDefId, def_kind: DefKind) -> | DefKind::AssocFn | DefKind::AssocConst | DefKind::Closure - | DefKind::Coroutine | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst => true, @@ -1218,7 +1210,6 @@ fn should_encode_fn_sig(def_kind: DefKind) -> bool { | DefKind::Impl { .. } | DefKind::AssocConst | DefKind::Closure - | DefKind::Coroutine | DefKind::ConstParam | DefKind::AnonConst | DefKind::InlineConst @@ -1257,7 +1248,6 @@ fn should_encode_constness(def_kind: DefKind) -> bool { | DefKind::OpaqueTy | DefKind::Impl { of_trait: false } | DefKind::ForeignTy - | DefKind::Coroutine | DefKind::ConstParam | DefKind::InlineConst | DefKind::AssocTy @@ -1292,7 +1282,6 @@ fn should_encode_const(def_kind: DefKind) -> bool { | DefKind::Impl { .. } | DefKind::AssocFn | DefKind::Closure - | DefKind::Coroutine | DefKind::ConstParam | DefKind::AssocTy | DefKind::TyParam @@ -1452,8 +1441,9 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { self.encode_info_for_assoc_item(def_id); } } - if let DefKind::Coroutine = def_kind { - let data = self.tcx.coroutine_kind(def_id).unwrap(); + if def_kind == DefKind::Closure + && let Some(data) = self.tcx.coroutine_kind(def_id) + { record!(self.tables.coroutine_kind[def_id] <- data); } if let DefKind::Enum | DefKind::Struct | DefKind::Union = def_kind { @@ -1635,7 +1625,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { record!(self.tables.closure_saved_names_of_captured_variables[def_id.to_def_id()] <- tcx.closure_saved_names_of_captured_variables(def_id)); - if let DefKind::Coroutine = self.tcx.def_kind(def_id) + if self.tcx.is_coroutine(def_id.to_def_id()) && let Some(witnesses) = tcx.mir_coroutine_witnesses(def_id) { record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses); @@ -1662,7 +1652,7 @@ impl<'a, 'tcx> EncodeContext<'a, 'tcx> { } record!(self.tables.promoted_mir[def_id.to_def_id()] <- tcx.promoted_mir(def_id)); - if let DefKind::Coroutine = self.tcx.def_kind(def_id) + if self.tcx.is_coroutine(def_id.to_def_id()) && let Some(witnesses) = tcx.mir_coroutine_witnesses(def_id) { record!(self.tables.mir_coroutine_witnesses[def_id.to_def_id()] <- witnesses); diff --git a/compiler/rustc_metadata/src/rmeta/table.rs b/compiler/rustc_metadata/src/rmeta/table.rs index 96cf668b7da8..7cdbcd9193cf 100644 --- a/compiler/rustc_metadata/src/rmeta/table.rs +++ b/compiler/rustc_metadata/src/rmeta/table.rs @@ -167,7 +167,6 @@ fixed_size_enum! { ( Impl { of_trait: false } ) ( Impl { of_trait: true } ) ( Closure ) - ( Coroutine ) ( Static(ast::Mutability::Not) ) ( Static(ast::Mutability::Mut) ) ( Ctor(CtorOf::Struct, CtorKind::Fn) ) diff --git a/compiler/rustc_middle/src/hir/map/mod.rs b/compiler/rustc_middle/src/hir/map/mod.rs index c1c2ac22bd39..2ab8faac5b41 100644 --- a/compiler/rustc_middle/src/hir/map/mod.rs +++ b/compiler/rustc_middle/src/hir/map/mod.rs @@ -236,8 +236,7 @@ impl<'hir> Map<'hir> { Node::ConstBlock(_) => DefKind::InlineConst, Node::Field(_) => DefKind::Field, Node::Expr(expr) => match expr.kind { - ExprKind::Closure(Closure { movability: None, .. }) => DefKind::Closure, - ExprKind::Closure(Closure { movability: Some(_), .. }) => DefKind::Coroutine, + ExprKind::Closure(_) => DefKind::Closure, _ => bug!("def_kind: unsupported node: {}", self.node_to_string(hir_id)), }, Node::GenericParam(param) => match param.kind { @@ -441,7 +440,7 @@ impl<'hir> Map<'hir> { } DefKind::InlineConst => BodyOwnerKind::Const { inline: true }, DefKind::Ctor(..) | DefKind::Fn | DefKind::AssocFn => BodyOwnerKind::Fn, - DefKind::Closure | DefKind::Coroutine => BodyOwnerKind::Closure, + DefKind::Closure => BodyOwnerKind::Closure, DefKind::Static(mt) => BodyOwnerKind::Static(mt), dk => bug!("{:?} is not a body node: {:?}", def_id, dk), } diff --git a/compiler/rustc_middle/src/ty/context.rs b/compiler/rustc_middle/src/ty/context.rs index 3e24b7cce867..22117d63e030 100644 --- a/compiler/rustc_middle/src/ty/context.rs +++ b/compiler/rustc_middle/src/ty/context.rs @@ -800,6 +800,10 @@ impl<'tcx> TyCtxt<'tcx> { self.diagnostic_items(did.krate).name_to_id.get(&name) == Some(&did) } + pub fn is_coroutine(self, def_id: DefId) -> bool { + self.coroutine_kind(def_id).is_some() + } + /// Returns `true` if the node pointed to by `def_id` is a coroutine for an async construct. pub fn coroutine_is_async(self, def_id: DefId) -> bool { matches!(self.coroutine_kind(def_id), Some(hir::CoroutineKind::Async(_))) diff --git a/compiler/rustc_middle/src/ty/util.rs b/compiler/rustc_middle/src/ty/util.rs index 77cf3c0041ca..cbf1a9900d9a 100644 --- a/compiler/rustc_middle/src/ty/util.rs +++ b/compiler/rustc_middle/src/ty/util.rs @@ -550,16 +550,13 @@ impl<'tcx> TyCtxt<'tcx> { /// those are not yet phased out). The parent of the closure's /// `DefId` will also be the context where it appears. pub fn is_closure(self, def_id: DefId) -> bool { - matches!(self.def_kind(def_id), DefKind::Closure | DefKind::Coroutine) + matches!(self.def_kind(def_id), DefKind::Closure) } /// Returns `true` if `def_id` refers to a definition that does not have its own /// type-checking context, i.e. closure, coroutine or inline const. pub fn is_typeck_child(self, def_id: DefId) -> bool { - matches!( - self.def_kind(def_id), - DefKind::Closure | DefKind::Coroutine | DefKind::InlineConst - ) + matches!(self.def_kind(def_id), DefKind::Closure | DefKind::InlineConst) } /// Returns `true` if `def_id` refers to a trait (i.e., `trait Foo { ... }`). @@ -732,11 +729,13 @@ impl<'tcx> TyCtxt<'tcx> { pub fn def_kind_descr(self, def_kind: DefKind, def_id: DefId) -> &'static str { match def_kind { DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "method", - DefKind::Coroutine => match self.coroutine_kind(def_id).unwrap() { - rustc_hir::CoroutineKind::Async(..) => "async closure", - rustc_hir::CoroutineKind::Coroutine => "coroutine", - rustc_hir::CoroutineKind::Gen(..) => "gen closure", - }, + DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { + match coroutine_kind { + rustc_hir::CoroutineKind::Async(..) => "async closure", + rustc_hir::CoroutineKind::Coroutine => "coroutine", + rustc_hir::CoroutineKind::Gen(..) => "gen closure", + } + } _ => def_kind.descr(def_id), } } @@ -750,11 +749,13 @@ impl<'tcx> TyCtxt<'tcx> { pub fn def_kind_descr_article(self, def_kind: DefKind, def_id: DefId) -> &'static str { match def_kind { DefKind::AssocFn if self.associated_item(def_id).fn_has_self_parameter => "a", - DefKind::Coroutine => match self.coroutine_kind(def_id).unwrap() { - rustc_hir::CoroutineKind::Async(..) => "an", - rustc_hir::CoroutineKind::Coroutine => "a", - rustc_hir::CoroutineKind::Gen(..) => "a", - }, + DefKind::Closure if let Some(coroutine_kind) = self.coroutine_kind(def_id) => { + match coroutine_kind { + rustc_hir::CoroutineKind::Async(..) => "an", + rustc_hir::CoroutineKind::Coroutine => "a", + rustc_hir::CoroutineKind::Gen(..) => "a", + } + } _ => def_kind.article(), } } diff --git a/compiler/rustc_mir_build/src/build/mod.rs b/compiler/rustc_mir_build/src/build/mod.rs index 3d2396f33fc0..40575fdf5f2e 100644 --- a/compiler/rustc_mir_build/src/build/mod.rs +++ b/compiler/rustc_mir_build/src/build/mod.rs @@ -638,6 +638,14 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - ); (sig.inputs().to_vec(), sig.output(), None) } + DefKind::Closure if coroutine_kind.is_some() => { + let coroutine_ty = tcx.type_of(def_id).instantiate_identity(); + let ty::Coroutine(_, args, _) = coroutine_ty.kind() else { bug!() }; + let args = args.as_coroutine(); + let yield_ty = args.yield_ty(); + let return_ty = args.return_ty(); + (vec![coroutine_ty, args.resume_ty()], return_ty, Some(yield_ty)) + } DefKind::Closure => { let closure_ty = tcx.type_of(def_id).instantiate_identity(); let ty::Closure(_, args) = closure_ty.kind() else { bug!() }; @@ -650,14 +658,6 @@ fn construct_error(tcx: TyCtxt<'_>, def_id: LocalDefId, guar: ErrorGuaranteed) - }; ([self_ty].into_iter().chain(sig.inputs().to_vec()).collect(), sig.output(), None) } - DefKind::Coroutine => { - let coroutine_ty = tcx.type_of(def_id).instantiate_identity(); - let ty::Coroutine(_, args, _) = coroutine_ty.kind() else { bug!() }; - let args = args.as_coroutine(); - let yield_ty = args.yield_ty(); - let return_ty = args.return_ty(); - (vec![coroutine_ty, args.resume_ty()], return_ty, Some(yield_ty)) - } dk => bug!("{:?} is not a body: {:?}", def_id, dk), }; diff --git a/compiler/rustc_mir_build/src/thir/cx/mod.rs b/compiler/rustc_mir_build/src/thir/cx/mod.rs index 0427f66db287..1663b1ddf61f 100644 --- a/compiler/rustc_mir_build/src/thir/cx/mod.rs +++ b/compiler/rustc_mir_build/src/thir/cx/mod.rs @@ -37,7 +37,7 @@ pub(crate) fn thir_body( // The resume argument may be missing, in that case we need to provide it here. // It will always be `()` in this case. - if tcx.def_kind(owner_def) == DefKind::Coroutine && body.params.is_empty() { + if tcx.is_coroutine(owner_def.to_def_id()) && body.params.is_empty() { cx.thir.params.push(Param { ty: Ty::new_unit(tcx), pat: None, @@ -119,6 +119,17 @@ impl<'tcx> Cx<'tcx> { fn closure_env_param(&self, owner_def: LocalDefId, owner_id: HirId) -> Option> { match self.tcx.def_kind(owner_def) { + DefKind::Closure if self.tcx.is_coroutine(owner_def.to_def_id()) => { + let coroutine_ty = self.typeck_results.node_type(owner_id); + let coroutine_param = Param { + ty: coroutine_ty, + pat: None, + ty_span: None, + self_kind: None, + hir_id: None, + }; + Some(coroutine_param) + } DefKind::Closure => { let closure_ty = self.typeck_results.node_type(owner_id); @@ -148,17 +159,6 @@ impl<'tcx> Cx<'tcx> { Some(env_param) } - DefKind::Coroutine => { - let coroutine_ty = self.typeck_results.node_type(owner_id); - let coroutine_param = Param { - ty: coroutine_ty, - pat: None, - ty_span: None, - self_kind: None, - hir_id: None, - }; - Some(coroutine_param) - } _ => None, } } diff --git a/compiler/rustc_mir_transform/src/const_prop.rs b/compiler/rustc_mir_transform/src/const_prop.rs index 42d33f4f5179..9a16003bdc9a 100644 --- a/compiler/rustc_mir_transform/src/const_prop.rs +++ b/compiler/rustc_mir_transform/src/const_prop.rs @@ -84,8 +84,7 @@ impl<'tcx> MirPass<'tcx> for ConstProp { // FIXME(welseywiser) const prop doesn't work on coroutines because of query cycles // computing their layout. - let is_coroutine = def_kind == DefKind::Coroutine; - if is_coroutine { + if tcx.is_coroutine(def_id.to_def_id()) { trace!("ConstProp skipped for coroutine {:?}", def_id); return; } diff --git a/compiler/rustc_mir_transform/src/const_prop_lint.rs b/compiler/rustc_mir_transform/src/const_prop_lint.rs index da315bb86ac6..99eecb567f27 100644 --- a/compiler/rustc_mir_transform/src/const_prop_lint.rs +++ b/compiler/rustc_mir_transform/src/const_prop_lint.rs @@ -61,7 +61,7 @@ impl<'tcx> MirLint<'tcx> for ConstPropLint { // FIXME(welseywiser) const prop doesn't work on coroutines because of query cycles // computing their layout. - if let DefKind::Coroutine = def_kind { + if tcx.is_coroutine(def_id.to_def_id()) { trace!("ConstPropLint skipped for coroutine {:?}", def_id); return; } diff --git a/compiler/rustc_mir_transform/src/lib.rs b/compiler/rustc_mir_transform/src/lib.rs index 5c05446a981b..fff760ba399b 100644 --- a/compiler/rustc_mir_transform/src/lib.rs +++ b/compiler/rustc_mir_transform/src/lib.rs @@ -395,7 +395,7 @@ fn inner_mir_for_ctfe(tcx: TyCtxt<'_>, def: LocalDefId) -> Body<'_> { /// mir borrowck *before* doing so in order to ensure that borrowck can be run and doesn't /// end up missing the source MIR due to stealing happening. fn mir_drops_elaborated_and_const_checked(tcx: TyCtxt<'_>, def: LocalDefId) -> &Steal> { - if let DefKind::Coroutine = tcx.def_kind(def) { + if tcx.is_coroutine(def.to_def_id()) { tcx.ensure_with_value().mir_coroutine_witnesses(def); } let mir_borrowck = tcx.mir_borrowck(def); diff --git a/compiler/rustc_monomorphize/src/polymorphize.rs b/compiler/rustc_monomorphize/src/polymorphize.rs index a3b35eab4658..91abbb216d66 100644 --- a/compiler/rustc_monomorphize/src/polymorphize.rs +++ b/compiler/rustc_monomorphize/src/polymorphize.rs @@ -131,7 +131,7 @@ fn mark_used_by_default_parameters<'tcx>( unused_parameters: &mut UnusedGenericParams, ) { match tcx.def_kind(def_id) { - DefKind::Closure | DefKind::Coroutine => { + DefKind::Closure => { for param in &generics.params { debug!(?param, "(closure/gen)"); unused_parameters.mark_used(param.index); @@ -248,7 +248,7 @@ impl<'a, 'tcx> Visitor<'tcx> for MarkUsedGenericParams<'a, 'tcx> { fn visit_local_decl(&mut self, local: Local, local_decl: &LocalDecl<'tcx>) { if local == Local::from_usize(1) { let def_kind = self.tcx.def_kind(self.def_id); - if matches!(def_kind, DefKind::Closure | DefKind::Coroutine) { + if matches!(def_kind, DefKind::Closure) { // Skip visiting the closure/coroutine that is currently being processed. This only // happens because the first argument to the closure is a reference to itself and // that will call `visit_args`, resulting in each generic parameter captured being diff --git a/compiler/rustc_privacy/src/lib.rs b/compiler/rustc_privacy/src/lib.rs index 51d12ebdc088..6a9715a44f20 100644 --- a/compiler/rustc_privacy/src/lib.rs +++ b/compiler/rustc_privacy/src/lib.rs @@ -653,8 +653,7 @@ impl<'tcx> EmbargoVisitor<'tcx> { | DefKind::Field | DefKind::GlobalAsm | DefKind::Impl { .. } - | DefKind::Closure - | DefKind::Coroutine => (), + | DefKind::Closure => (), } } } diff --git a/compiler/rustc_resolve/src/build_reduced_graph.rs b/compiler/rustc_resolve/src/build_reduced_graph.rs index 60a28e3a1a4b..65901eedb214 100644 --- a/compiler/rustc_resolve/src/build_reduced_graph.rs +++ b/compiler/rustc_resolve/src/build_reduced_graph.rs @@ -973,8 +973,7 @@ impl<'a, 'b, 'tcx> BuildReducedGraphVisitor<'a, 'b, 'tcx> { | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Closure - | DefKind::Impl { .. } - | DefKind::Coroutine, + | DefKind::Impl { .. }, _, ) | Res::Local(..) diff --git a/compiler/rustc_smir/src/rustc_smir/mod.rs b/compiler/rustc_smir/src/rustc_smir/mod.rs index 5d903e69c6cd..eee587f3b2ab 100644 --- a/compiler/rustc_smir/src/rustc_smir/mod.rs +++ b/compiler/rustc_smir/src/rustc_smir/mod.rs @@ -89,7 +89,7 @@ pub(crate) fn new_item_kind(kind: DefKind) -> ItemKind { | DefKind::GlobalAsm => { unreachable!("Not a valid item kind: {kind:?}"); } - DefKind::Closure | DefKind::Coroutine | DefKind::AssocFn | DefKind::Fn => ItemKind::Fn, + DefKind::Closure | DefKind::AssocFn | DefKind::Fn => ItemKind::Fn, DefKind::Const | DefKind::InlineConst | DefKind::AssocConst | DefKind::AnonConst => { ItemKind::Const } diff --git a/compiler/rustc_symbol_mangling/src/lib.rs b/compiler/rustc_symbol_mangling/src/lib.rs index 9f0982d09957..311b94d9e0e6 100644 --- a/compiler/rustc_symbol_mangling/src/lib.rs +++ b/compiler/rustc_symbol_mangling/src/lib.rs @@ -234,7 +234,7 @@ fn compute_symbol_name<'tcx>( // and we want to be sure to avoid any symbol conflicts here. let is_globally_shared_function = matches!( tcx.def_kind(instance.def_id()), - DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Coroutine | DefKind::Ctor(..) + DefKind::Fn | DefKind::AssocFn | DefKind::Closure | DefKind::Ctor(..) ) && matches!( MonoItem::Fn(instance).instantiation_mode(tcx), InstantiationMode::GloballyShared { may_conflict: true } diff --git a/compiler/rustc_ty_utils/src/implied_bounds.rs b/compiler/rustc_ty_utils/src/implied_bounds.rs index 6cf5aa6f2fb3..eef90dc6dac6 100644 --- a/compiler/rustc_ty_utils/src/implied_bounds.rs +++ b/compiler/rustc_ty_utils/src/implied_bounds.rs @@ -156,8 +156,7 @@ fn assumed_wf_types<'tcx>(tcx: TyCtxt<'tcx>, def_id: LocalDefId) -> &'tcx [(Ty<' | DefKind::Field | DefKind::LifetimeParam | DefKind::GlobalAsm - | DefKind::Closure - | DefKind::Coroutine => ty::List::empty(), + | DefKind::Closure => ty::List::empty(), } } diff --git a/compiler/rustc_ty_utils/src/opaque_types.rs b/compiler/rustc_ty_utils/src/opaque_types.rs index 7ca2da42042b..d9add1f210bb 100644 --- a/compiler/rustc_ty_utils/src/opaque_types.rs +++ b/compiler/rustc_ty_utils/src/opaque_types.rs @@ -313,7 +313,7 @@ fn opaque_types_defined_by<'tcx>( | DefKind::Impl { .. } => {} // Closures and coroutines are type checked with their parent, so we need to allow all // opaques from the closure signature *and* from the parent body. - DefKind::Closure | DefKind::Coroutine | DefKind::InlineConst => { + DefKind::Closure | DefKind::InlineConst => { collector.opaques.extend(tcx.opaque_types_defined_by(tcx.local_parent(item))); } } diff --git a/compiler/rustc_ty_utils/src/sig_types.rs b/compiler/rustc_ty_utils/src/sig_types.rs index 268639a7f444..7c0261c818f5 100644 --- a/compiler/rustc_ty_utils/src/sig_types.rs +++ b/compiler/rustc_ty_utils/src/sig_types.rs @@ -67,7 +67,7 @@ pub(crate) fn walk_types<'tcx, V: SpannedTypeVisitor<'tcx>>( // These are not part of a public API, they can only appear as hidden types, and there // the interesting parts are solely in the signature of the containing item's opaque type // or dyn type. - DefKind::InlineConst | DefKind::Closure | DefKind::Coroutine => {} + DefKind::InlineConst | DefKind::Closure => {} DefKind::Impl { of_trait } => { if of_trait { let span = tcx.hir().get_by_def_id(item).expect_item().expect_impl().of_trait.unwrap().path.span; diff --git a/src/librustdoc/formats/item_type.rs b/src/librustdoc/formats/item_type.rs index 5666751d1ce9..e80da46adb4c 100644 --- a/src/librustdoc/formats/item_type.rs +++ b/src/librustdoc/formats/item_type.rs @@ -149,8 +149,7 @@ impl From for ItemType { | DefKind::LifetimeParam | DefKind::GlobalAsm | DefKind::Impl { .. } - | DefKind::Closure - | DefKind::Coroutine => Self::ForeignType, + | DefKind::Closure => Self::ForeignType, } } } diff --git a/src/librustdoc/passes/collect_intra_doc_links.rs b/src/librustdoc/passes/collect_intra_doc_links.rs index 1e8ece7e114a..6b536e97c43c 100644 --- a/src/librustdoc/passes/collect_intra_doc_links.rs +++ b/src/librustdoc/passes/collect_intra_doc_links.rs @@ -1924,7 +1924,6 @@ fn resolution_failure( Variant | Field | Closure - | Coroutine | AssocTy | AssocConst | AssocFn From 4a22b1aa1c72c61e2e7dd8d19bceca4bd3318434 Mon Sep 17 00:00:00 2001 From: Waffle Maybe Date: Sun, 26 Nov 2023 15:33:34 +0100 Subject: [PATCH 85/93] Remove myself from users on vacation --- triagebot.toml | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/triagebot.toml b/triagebot.toml index c1482769852b..593386288b49 100644 --- a/triagebot.toml +++ b/triagebot.toml @@ -626,7 +626,7 @@ cc = ["@nnethercote"] [assign] warn_non_default_branch = true contributing_url = "https://rustc-dev-guide.rust-lang.org/getting-started.html" -users_on_vacation = ["jyn514", "WaffleLapkin", "oli-obk"] +users_on_vacation = ["jyn514", "oli-obk"] [assign.adhoc_groups] compiler-team = [ From 36a587fb62ec903297b2e43918a4d28814a31e99 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 7 Nov 2023 23:15:11 +0000 Subject: [PATCH 86/93] Add read/write/copy convenience methods to `NonNull` --- library/core/src/ptr/non_null.rs | 237 +++++++++++++++++++++++++++++-- 1 file changed, 223 insertions(+), 14 deletions(-) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index ae673b7799ff..3177e3975d29 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -2,11 +2,14 @@ use crate::cmp::Ordering; use crate::convert::From; use crate::fmt; use crate::hash; +use crate::intrinsics; use crate::intrinsics::assert_unsafe_precondition; use crate::marker::Unsize; +use crate::mem::SizedTypeProperties; use crate::mem::{self, MaybeUninit}; use crate::num::NonZeroUsize; use crate::ops::{CoerceUnsized, DispatchFromDyn}; +use crate::ptr; use crate::ptr::Unique; use crate::slice::{self, SliceIndex}; @@ -471,30 +474,236 @@ impl NonNull { unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) } } - /// See [`pointer::add`] for semantics and safety requirements. + /// Reads the value from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// See [`ptr::read`] for safety concerns and examples. + /// + /// [`ptr::read`]: crate::ptr::read() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] #[inline] - pub(crate) const unsafe fn add(self, delta: usize) -> Self + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn read(self) -> T where T: Sized, { - // SAFETY: We require that the delta stays in-bounds of the object, and - // thus it cannot become null, as that would require wrapping the - // address space, which no legal objects are allowed to do. - // And the caller promised the `delta` is sound to add. - unsafe { NonNull { pointer: self.pointer.add(delta) } } + // SAFETY: the caller must uphold the safety contract for `read`. + unsafe { ptr::read(self.pointer) } } - /// See [`pointer::sub`] for semantics and safety requirements. + /// Performs a volatile read of the value from `self` without moving it. This + /// leaves the memory in `self` unchanged. + /// + /// Volatile operations are intended to act on I/O memory, and are guaranteed + /// to not be elided or reordered by the compiler across other volatile + /// operations. + /// + /// See [`ptr::read_volatile`] for safety concerns and examples. + /// + /// [`ptr::read_volatile`]: crate::ptr::read_volatile() + #[unstable(feature = "non_null_convenience", issue = "117691")] #[inline] - pub(crate) const unsafe fn sub(self, delta: usize) -> Self + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub unsafe fn read_volatile(self) -> T where T: Sized, { - // SAFETY: We require that the delta stays in-bounds of the object, and - // thus it cannot become null, as no legal objects can be allocated - // in such as way that the null address is part of them. - // And the caller promised the `delta` is sound to subtract. - unsafe { NonNull { pointer: self.pointer.sub(delta) } } + // SAFETY: the caller must uphold the safety contract for `read_volatile`. + unsafe { ptr::read_volatile(self.pointer) } + } + + /// Reads the value from `self` without moving it. This leaves the + /// memory in `self` unchanged. + /// + /// Unlike `read`, the pointer may be unaligned. + /// + /// See [`ptr::read_unaligned`] for safety concerns and examples. + /// + /// [`ptr::read_unaligned`]: crate::ptr::read_unaligned() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn read_unaligned(self) -> T + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `read_unaligned`. + unsafe { ptr::read_unaligned(self.pointer) } + } + + /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// and destination may overlap. + /// + /// NOTE: this has the *same* argument order as [`ptr::copy`]. + /// + /// See [`ptr::copy`] for safety concerns and examples. + /// + /// [`ptr::copy`]: crate::ptr::copy() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn copy_to(self, dest: NonNull, count: usize) + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `copy`. + unsafe { ptr::copy(self.pointer, dest.as_ptr(), count) } + } + + /// Copies `count * size_of` bytes from `self` to `dest`. The source + /// and destination may *not* overlap. + /// + /// NOTE: this has the *same* argument order as [`ptr::copy_nonoverlapping`]. + /// + /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. + /// + /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn copy_to_nonoverlapping(self, dest: NonNull, count: usize) + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `copy_nonoverlapping`. + unsafe { ptr::copy_nonoverlapping(self.pointer, dest.as_ptr(), count) } + } + + /// Copies `count * size_of` bytes from `src` to `self`. The source + /// and destination may overlap. + /// + /// NOTE: this has the *opposite* argument order of [`ptr::copy`]. + /// + /// See [`ptr::copy`] for safety concerns and examples. + /// + /// [`ptr::copy`]: crate::ptr::copy() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn copy_from(self, src: NonNull, count: usize) + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `copy`. + unsafe { ptr::copy(src.pointer, self.as_ptr(), count) } + } + + /// Copies `count * size_of` bytes from `src` to `self`. The source + /// and destination may *not* overlap. + /// + /// NOTE: this has the *opposite* argument order of [`ptr::copy_nonoverlapping`]. + /// + /// See [`ptr::copy_nonoverlapping`] for safety concerns and examples. + /// + /// [`ptr::copy_nonoverlapping`]: crate::ptr::copy_nonoverlapping() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn copy_from_nonoverlapping(self, src: NonNull, count: usize) + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `copy_nonoverlapping`. + unsafe { ptr::copy_nonoverlapping(src.pointer, self.as_ptr(), count) } + } + + /// Executes the destructor (if any) of the pointed-to value. + /// + /// See [`ptr::drop_in_place`] for safety concerns and examples. + /// + /// [`ptr::drop_in_place`]: crate::ptr::drop_in_place() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[inline(always)] + pub unsafe fn drop_in_place(self) { + // SAFETY: the caller must uphold the safety contract for `drop_in_place`. + unsafe { ptr::drop_in_place(self.as_ptr()) } + } + + /// Overwrites a memory location with the given value without reading or + /// dropping the old value. + /// + /// See [`ptr::write`] for safety concerns and examples. + /// + /// [`ptr::write`]: crate::ptr::write() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + //#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn write(self, val: T) + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `write`. + unsafe { ptr::write(self.as_ptr(), val) } + } + + /// Invokes memset on the specified pointer, setting `count * size_of::()` + /// bytes of memory starting at `self` to `val`. + /// + /// See [`ptr::write_bytes`] for safety concerns and examples. + /// + /// [`ptr::write_bytes`]: crate::ptr::write_bytes() + #[doc(alias = "memset")] + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + //#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn write_bytes(self, val: u8, count: usize) + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `write_bytes`. + unsafe { ptr::write_bytes(self.as_ptr(), val, count) } + } + + /// Performs a volatile write of a memory location with the given value without + /// reading or dropping the old value. + /// + /// Volatile operations are intended to act on I/O memory, and are guaranteed + /// to not be elided or reordered by the compiler across other volatile + /// operations. + /// + /// See [`ptr::write_volatile`] for safety concerns and examples. + /// + /// [`ptr::write_volatile`]: crate::ptr::write_volatile() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub unsafe fn write_volatile(self, val: T) + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `write_volatile`. + unsafe { ptr::write_volatile(self.as_ptr(), val) } + } + + /// Overwrites a memory location with the given value without reading or + /// dropping the old value. + /// + /// Unlike `write`, the pointer may be unaligned. + /// + /// See [`ptr::write_unaligned`] for safety concerns and examples. + /// + /// [`ptr::write_unaligned`]: crate::ptr::write_unaligned() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + //#[rustc_const_unstable(feature = "const_ptr_write", issue = "86302")] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn write_unaligned(self, val: T) + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `write_unaligned`. + unsafe { ptr::write_unaligned(self.as_ptr(), val) } } /// See [`pointer::sub_ptr`] for semantics and safety requirements. From ebdc79497fe8e3fce63d20d336d84711fe73018d Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Tue, 7 Nov 2023 23:55:00 +0000 Subject: [PATCH 87/93] Add offset-ish convenience methods to `NonNull` --- library/core/src/lib.rs | 1 + library/core/src/ptr/non_null.rs | 273 +++++++++++++++++++++++++++++++ 2 files changed, 274 insertions(+) diff --git a/library/core/src/lib.rs b/library/core/src/lib.rs index d44cf299c278..86f5fc56361c 100644 --- a/library/core/src/lib.rs +++ b/library/core/src/lib.rs @@ -178,6 +178,7 @@ #![feature(is_ascii_octdigit)] #![feature(isqrt)] #![feature(maybe_uninit_uninit_array)] +#![feature(non_null_convenience)] #![feature(offset_of)] #![feature(offset_of_enum)] #![feature(ptr_alignment_type)] diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 3177e3975d29..7eb17c7c9fbb 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -474,6 +474,279 @@ impl NonNull { unsafe { NonNull::new_unchecked(self.as_ptr() as *mut U) } } + /// Calculates the offset from a pointer. + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same [allocated object]. + /// + /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum, **in bytes** must fit in a usize. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// [allocated object]: crate::ptr#allocated-object + /// + /// # Examples + /// + /// ``` + /// #![feature(non_null_convenience)] + /// use std::ptr::NonNull; + /// + /// let mut s = [1, 2, 3]; + /// let ptr: NonNull = NonNull::new(s.as_mut_ptr()).unwrap(); + /// + /// unsafe { + /// println!("{}", ptr.offset(1).read()); + /// println!("{}", ptr.offset(2).read()); + /// } + /// ``` + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[must_use = "returns a new pointer rather than modifying its argument"] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn offset(self, count: isize) -> NonNull + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `offset`. + // Additionally safety contract of `offset` guarantees that the resulting pointer is + // pointing to an allocation, there can't be an allocation at null, thus it's safe to + // construct `NonNull`. + unsafe { NonNull { pointer: intrinsics::offset(self.pointer, count) } } + } + + /// Calculates the offset from a pointer in bytes. + /// + /// `count` is in units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [offset][pointer::offset] on it. See that method for documentation + /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[must_use] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn byte_offset(self, count: isize) -> Self { + // SAFETY: the caller must uphold the safety contract for `offset` and `byte_offset` has + // the same safety contract. + // Additionally safety contract of `offset` guarantees that the resulting pointer is + // pointing to an allocation, there can't be an allocation at null, thus it's safe to + // construct `NonNull`. + unsafe { NonNull { pointer: self.pointer.byte_offset(count) } } + } + + /// Calculates the offset from a pointer (convenience for `.offset(count as isize)`). + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same [allocated object]. + /// + /// * The computed offset, **in bytes**, cannot overflow an `isize`. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum must fit in a `usize`. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// [allocated object]: crate::ptr#allocated-object + /// + /// # Examples + /// + /// ``` + /// #![feature(non_null_convenience)] + /// use std::ptr::NonNull; + /// + /// let s: &str = "123"; + /// let ptr: NonNull = NonNull::new(s.as_ptr().cast_mut()).unwrap(); + /// + /// unsafe { + /// println!("{}", ptr.add(1).read() as char); + /// println!("{}", ptr.add(2).read() as char); + /// } + /// ``` + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[must_use = "returns a new pointer rather than modifying its argument"] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn add(self, count: usize) -> Self + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `offset`. + // Additionally safety contract of `offset` guarantees that the resulting pointer is + // pointing to an allocation, there can't be an allocation at null, thus it's safe to + // construct `NonNull`. + unsafe { NonNull { pointer: intrinsics::offset(self.pointer, count) } } + } + + /// Calculates the offset from a pointer in bytes (convenience for `.byte_offset(count as isize)`). + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [`add`][NonNull::add] on it. See that method for documentation + /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[must_use] + #[inline(always)] + #[rustc_allow_const_fn_unstable(set_ptr_value)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn byte_add(self, count: usize) -> Self { + // SAFETY: the caller must uphold the safety contract for `add` and `byte_add` has the same + // safety contract. + // Additionally safety contract of `add` guarantees that the resulting pointer is pointing + // to an allocation, there can't be an allocation at null, thus it's safe to construct + // `NonNull`. + unsafe { NonNull { pointer: self.pointer.byte_add(count) } } + } + + /// Calculates the offset from a pointer (convenience for + /// `.offset((count as isize).wrapping_neg())`). + /// + /// `count` is in units of T; e.g., a `count` of 3 represents a pointer + /// offset of `3 * size_of::()` bytes. + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both the starting and resulting pointer must be either in bounds or one + /// byte past the end of the same [allocated object]. + /// + /// * The computed offset cannot exceed `isize::MAX` **bytes**. + /// + /// * The offset being in bounds cannot rely on "wrapping around" the address + /// space. That is, the infinite-precision sum must fit in a usize. + /// + /// The compiler and standard library generally tries to ensure allocations + /// never reach a size where an offset is a concern. For instance, `Vec` + /// and `Box` ensure they never allocate more than `isize::MAX` bytes, so + /// `vec.as_ptr().add(vec.len()).sub(vec.len())` is always safe. + /// + /// Most platforms fundamentally can't even construct such an allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// + /// [allocated object]: crate::ptr#allocated-object + /// + /// # Examples + /// + /// ``` + /// #![feature(non_null_convenience)] + /// use std::ptr::NonNull; + /// + /// let s: &str = "123"; + /// + /// unsafe { + /// let end: NonNull = NonNull::new(s.as_ptr().cast_mut()).unwrap().add(3); + /// println!("{}", end.sub(1).read() as char); + /// println!("{}", end.sub(2).read() as char); + /// } + /// ``` + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[must_use = "returns a new pointer rather than modifying its argument"] + // We could always go back to wrapping if unchecked becomes unacceptable + #[rustc_allow_const_fn_unstable(const_int_unchecked_arith)] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn sub(self, count: usize) -> Self + where + T: Sized, + { + if T::IS_ZST { + // Pointer arithmetic does nothing when the pointee is a ZST. + self + } else { + // SAFETY: the caller must uphold the safety contract for `offset`. + // Because the pointee is *not* a ZST, that means that `count` is + // at most `isize::MAX`, and thus the negation cannot overflow. + unsafe { self.offset(intrinsics::unchecked_sub(0, count as isize)) } + } + } + + /// Calculates the offset from a pointer in bytes (convenience for + /// `.byte_offset((count as isize).wrapping_neg())`). + /// + /// `count` is in units of bytes. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [`sub`][NonNull::sub] on it. See that method for documentation + /// and safety requirements. + /// + /// For non-`Sized` pointees this operation changes only the data pointer, + /// leaving the metadata untouched. + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[must_use] + #[inline(always)] + #[rustc_allow_const_fn_unstable(set_ptr_value)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn byte_sub(self, count: usize) -> Self { + // SAFETY: the caller must uphold the safety contract for `sub` and `byte_sub` has the same + // safety contract. + // Additionally safety contract of `sub` guarantees that the resulting pointer is pointing + // to an allocation, there can't be an allocation at null, thus it's safe to construct + // `NonNull`. + unsafe { NonNull { pointer: self.pointer.byte_sub(count) } } + } + + // N.B. `wrapping_offset``, `wrapping_add`, etc are not implemented because they can wrap to null + /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// From 4bcdd3bd92d1c4c6b2ebe9299b861aecd8b5f17a Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 8 Nov 2023 01:10:40 +0000 Subject: [PATCH 88/93] Add `offset_from`-ish convenience methods to `NonNull` --- library/core/src/ptr/non_null.rs | 220 +++++++++++++++++++++++++++++-- 1 file changed, 209 insertions(+), 11 deletions(-) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 7eb17c7c9fbb..1efff12ebc94 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -745,8 +745,217 @@ impl NonNull { unsafe { NonNull { pointer: self.pointer.byte_sub(count) } } } + /// Calculates the distance between two pointers. The returned value is in + /// units of T: the distance in bytes divided by `mem::size_of::()`. + /// + /// This is equivalent to `(self as isize - origin as isize) / (mem::size_of::() as isize)`, + /// except that it has a lot more opportunities for UB, in exchange for the compiler + /// better understanding what you are doing. + /// + /// The primary motivation of this method is for computing the `len` of an array/slice + /// of `T` that you are currently representing as a "start" and "end" pointer + /// (and "end" is "one past the end" of the array). + /// In that case, `end.offset_from(start)` gets you the length of the array. + /// + /// All of the following safety requirements are trivially satisfied for this usecase. + /// + /// [`offset`]: #method.offset + /// + /// # Safety + /// + /// If any of the following conditions are violated, the result is Undefined + /// Behavior: + /// + /// * Both `self` and `origin` must be either in bounds or one + /// byte past the end of the same [allocated object]. + /// + /// * Both pointers must be *derived from* a pointer to the same object. + /// (See below for an example.) + /// + /// * The distance between the pointers, in bytes, must be an exact multiple + /// of the size of `T`. + /// + /// * The distance between the pointers, **in bytes**, cannot overflow an `isize`. + /// + /// * The distance being in bounds cannot rely on "wrapping around" the address space. + /// + /// Rust types are never larger than `isize::MAX` and Rust allocations never wrap around the + /// address space, so two pointers within some value of any Rust type `T` will always satisfy + /// the last two conditions. The standard library also generally ensures that allocations + /// never reach a size where an offset is a concern. For instance, `Vec` and `Box` ensure they + /// never allocate more than `isize::MAX` bytes, so `ptr_into_vec.offset_from(vec.as_ptr())` + /// always satisfies the last two conditions. + /// + /// Most platforms fundamentally can't even construct such a large allocation. + /// For instance, no known 64-bit platform can ever serve a request + /// for 263 bytes due to page-table limitations or splitting the address space. + /// However, some 32-bit and 16-bit platforms may successfully serve a request for + /// more than `isize::MAX` bytes with things like Physical Address + /// Extension. As such, memory acquired directly from allocators or memory + /// mapped files *may* be too large to handle with this function. + /// (Note that [`offset`] and [`add`] also have a similar limitation and hence cannot be used on + /// such large allocations either.) + /// + /// The requirement for pointers to be derived from the same allocated object is primarily + /// needed for `const`-compatibility: the distance between pointers into *different* allocated + /// objects is not known at compile-time. However, the requirement also exists at + /// runtime and may be exploited by optimizations. If you wish to compute the difference between + /// pointers that are not guaranteed to be from the same allocation, use `(self as isize - + /// origin as isize) / mem::size_of::()`. + // FIXME: recommend `addr()` instead of `as usize` once that is stable. + /// + /// [`add`]: #method.add + /// [allocated object]: crate::ptr#allocated-object + /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// + /// # Examples + /// + /// Basic usage: + /// + /// ``` + /// #![feature(non_null_convenience)] + /// use std::ptr::NonNull; + /// + /// let a = [0; 5]; + /// let ptr1: NonNull = NonNull::from(&a[1]); + /// let ptr2: NonNull = NonNull::from(&a[3]); + /// unsafe { + /// assert_eq!(ptr2.offset_from(ptr1), 2); + /// assert_eq!(ptr1.offset_from(ptr2), -2); + /// assert_eq!(ptr1.offset(2), ptr2); + /// assert_eq!(ptr2.offset(-2), ptr1); + /// } + /// ``` + /// + /// *Incorrect* usage: + /// + /// ```rust,no_run + /// #![feature(non_null_convenience, strict_provenance)] + /// use std::ptr::NonNull; + /// + /// let ptr1 = NonNull::new(Box::into_raw(Box::new(0u8))).unwrap(); + /// let ptr2 = NonNull::new(Box::into_raw(Box::new(1u8))).unwrap(); + /// let diff = (ptr2.addr().get() as isize).wrapping_sub(ptr1.addr().get() as isize); + /// // Make ptr2_other an "alias" of ptr2, but derived from ptr1. + /// let ptr2_other = NonNull::new(ptr1.as_ptr().wrapping_byte_offset(diff)).unwrap(); + /// assert_eq!(ptr2.addr(), ptr2_other.addr()); + /// // Since ptr2_other and ptr2 are derived from pointers to different objects, + /// // computing their offset is undefined behavior, even though + /// // they point to the same address! + /// unsafe { + /// let zero = ptr2_other.offset_from(ptr2); // Undefined Behavior + /// } + /// ``` + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn offset_from(self, origin: NonNull) -> isize + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `offset_from`. + unsafe { self.pointer.offset_from(origin.pointer) } + } + + /// Calculates the distance between two pointers. The returned value is in + /// units of **bytes**. + /// + /// This is purely a convenience for casting to a `u8` pointer and + /// using [`offset_from`][NonNull::offset_from] on it. See that method for + /// documentation and safety requirements. + /// + /// For non-`Sized` pointees this operation considers only the data pointers, + /// ignoring the metadata. + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + #[inline(always)] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn byte_offset_from(self, origin: NonNull) -> isize { + // SAFETY: the caller must uphold the safety contract for `byte_offset_from`. + unsafe { self.pointer.byte_offset_from(origin.pointer) } + } + // N.B. `wrapping_offset``, `wrapping_add`, etc are not implemented because they can wrap to null + /// Calculates the distance between two pointers, *where it's known that + /// `self` is equal to or greater than `origin`*. The returned value is in + /// units of T: the distance in bytes is divided by `mem::size_of::()`. + /// + /// This computes the same value that [`offset_from`](#method.offset_from) + /// would compute, but with the added precondition that the offset is + /// guaranteed to be non-negative. This method is equivalent to + /// `usize::try_from(self.offset_from(origin)).unwrap_unchecked()`, + /// but it provides slightly more information to the optimizer, which can + /// sometimes allow it to optimize slightly better with some backends. + /// + /// This method can be though of as recovering the `count` that was passed + /// to [`add`](#method.add) (or, with the parameters in the other order, + /// to [`sub`](#method.sub)). The following are all equivalent, assuming + /// that their safety preconditions are met: + /// ```rust + /// # #![feature(non_null_convenience)] + /// # unsafe fn blah(ptr: std::ptr::NonNull, origin: std::ptr::NonNull, count: usize) -> bool { + /// ptr.sub_ptr(origin) == count + /// # && + /// origin.add(count) == ptr + /// # && + /// ptr.sub(count) == origin + /// # } + /// ``` + /// + /// # Safety + /// + /// - The distance between the pointers must be non-negative (`self >= origin`) + /// + /// - *All* the safety conditions of [`offset_from`](#method.offset_from) + /// apply to this method as well; see it for the full details. + /// + /// Importantly, despite the return type of this method being able to represent + /// a larger offset, it's still *not permitted* to pass pointers which differ + /// by more than `isize::MAX` *bytes*. As such, the result of this method will + /// always be less than or equal to `isize::MAX as usize`. + /// + /// # Panics + /// + /// This function panics if `T` is a Zero-Sized Type ("ZST"). + /// + /// # Examples + /// + /// ``` + /// #![feature(non_null_convenience)] + /// use std::ptr::NonNull; + /// + /// let a = [0; 5]; + /// let ptr1: NonNull = NonNull::from(&a[1]); + /// let ptr2: NonNull = NonNull::from(&a[3]); + /// unsafe { + /// assert_eq!(ptr2.sub_ptr(ptr1), 2); + /// assert_eq!(ptr1.add(2), ptr2); + /// assert_eq!(ptr2.sub(2), ptr1); + /// assert_eq!(ptr2.sub_ptr(ptr2), 0); + /// } + /// + /// // This would be incorrect, as the pointers are not correctly ordered: + /// // ptr1.sub_ptr(ptr2) + /// ``` + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + // #[unstable(feature = "ptr_sub_ptr", issue = "95892")] + // #[rustc_const_unstable(feature = "const_ptr_sub_ptr", issue = "95892")] + #[inline] + #[cfg_attr(miri, track_caller)] // even without panics, this helps for Miri backtraces + pub const unsafe fn sub_ptr(self, subtracted: NonNull) -> usize + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `sub_ptr`. + unsafe { self.pointer.sub_ptr(subtracted.pointer) } + } + /// Reads the value from `self` without moving it. This leaves the /// memory in `self` unchanged. /// @@ -978,17 +1187,6 @@ impl NonNull { // SAFETY: the caller must uphold the safety contract for `write_unaligned`. unsafe { ptr::write_unaligned(self.as_ptr(), val) } } - - /// See [`pointer::sub_ptr`] for semantics and safety requirements. - #[inline] - pub(crate) const unsafe fn sub_ptr(self, subtrahend: Self) -> usize - where - T: Sized, - { - // SAFETY: The caller promised that this is safe to do, and - // the non-nullness is irrelevant to the operation. - unsafe { self.pointer.sub_ptr(subtrahend.pointer) } - } } impl NonNull<[T]> { From 4cc46df98cd77abf141ac5c656bbc6234e260bd8 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 8 Nov 2023 01:24:58 +0000 Subject: [PATCH 89/93] Add `replace` and `swap` convenience methods to `NonNull` --- library/core/src/ptr/non_null.rs | 35 ++++++++++++++++++++++++++++++++ 1 file changed, 35 insertions(+) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 1efff12ebc94..6e92ea86dd02 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1187,6 +1187,41 @@ impl NonNull { // SAFETY: the caller must uphold the safety contract for `write_unaligned`. unsafe { ptr::write_unaligned(self.as_ptr(), val) } } + + /// Replaces the value at `self` with `src`, returning the old + /// value, without dropping either. + /// + /// See [`ptr::replace`] for safety concerns and examples. + /// + /// [`ptr::replace`]: crate::ptr::replace() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[inline(always)] + pub unsafe fn replace(self, src: T) -> T + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `replace`. + unsafe { ptr::replace(self.as_ptr(), src) } + } + + /// Swaps the values at two mutable locations of the same type, without + /// deinitializing either. They may overlap, unlike `mem::swap` which is + /// otherwise equivalent. + /// + /// See [`ptr::swap`] for safety concerns and examples. + /// + /// [`ptr::swap`]: crate::ptr::swap() + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + //#[rustc_const_unstable(feature = "const_swap", issue = "83163")] + #[inline(always)] + pub const unsafe fn swap(self, with: NonNull) + where + T: Sized, + { + // SAFETY: the caller must uphold the safety contract for `swap`. + unsafe { ptr::swap(self.as_ptr(), with.as_ptr()) } + } } impl NonNull<[T]> { From 2bcaa9760e771126ebb2aba6e4ae8930c6bafe79 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 8 Nov 2023 01:32:03 +0000 Subject: [PATCH 90/93] Add `align_offset` convenience method to `NonNull` --- library/core/src/ptr/non_null.rs | 60 ++++++++++++++++++++++++++++++++ 1 file changed, 60 insertions(+) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 6e92ea86dd02..748855e3ee3a 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1222,6 +1222,66 @@ impl NonNull { // SAFETY: the caller must uphold the safety contract for `swap`. unsafe { ptr::swap(self.as_ptr(), with.as_ptr()) } } + + /// Computes the offset that needs to be applied to the pointer in order to make it aligned to + /// `align`. + /// + /// If it is not possible to align the pointer, the implementation returns + /// `usize::MAX`. It is permissible for the implementation to *always* + /// return `usize::MAX`. Only your algorithm's performance can depend + /// on getting a usable offset here, not its correctness. + /// + /// The offset is expressed in number of `T` elements, and not bytes. + /// + /// There are no guarantees whatsoever that offsetting the pointer will not overflow or go + /// beyond the allocation that the pointer points into. It is up to the caller to ensure that + /// the returned offset is correct in all terms other than alignment. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two. + /// + /// # Examples + /// + /// Accessing adjacent `u8` as `u16` + /// + /// ``` + /// #![feature(non_null_convenience)] + /// use std::mem::align_of; + /// use std::ptr::NonNull; + /// + /// # unsafe { + /// let x = [5_u8, 6, 7, 8, 9]; + /// let ptr = NonNull::new(x.as_ptr() as *mut u8).unwrap(); + /// let offset = ptr.align_offset(align_of::()); + /// + /// if offset < x.len() - 1 { + /// let u16_ptr = ptr.add(offset).cast::(); + /// assert!(u16_ptr.read() == u16::from_ne_bytes([5, 6]) || u16_ptr.read() == u16::from_ne_bytes([6, 7])); + /// } else { + /// // while the pointer can be aligned via `offset`, it would point + /// // outside the allocation + /// } + /// # } + /// ``` + #[unstable(feature = "non_null_convenience", issue = "117691")] + #[rustc_const_unstable(feature = "non_null_convenience", issue = "117691")] + //#[rustc_const_unstable(feature = "const_align_offset", issue = "90962")] + #[must_use] + #[inline] + pub const fn align_offset(self, align: usize) -> usize + where + T: Sized, + { + if !align.is_power_of_two() { + panic!("align_offset: align is not a power-of-two"); + } + + { + // SAFETY: `align` has been checked to be a power of 2 above. + unsafe { ptr::align_offset(self.pointer, align) } + } + } } impl NonNull<[T]> { From e1b4e8a257ee0c1663f0e8dbb8832808cf0d9948 Mon Sep 17 00:00:00 2001 From: Maybe Waffle Date: Wed, 8 Nov 2023 02:03:22 +0000 Subject: [PATCH 91/93] Add `is_aligned{,_to}` convenience methods to `NonNull` --- library/core/src/ptr/non_null.rs | 234 +++++++++++++++++++++++++++++++ 1 file changed, 234 insertions(+) diff --git a/library/core/src/ptr/non_null.rs b/library/core/src/ptr/non_null.rs index 748855e3ee3a..c99fe36de6d8 100644 --- a/library/core/src/ptr/non_null.rs +++ b/library/core/src/ptr/non_null.rs @@ -1282,6 +1282,240 @@ impl NonNull { unsafe { ptr::align_offset(self.pointer, align) } } } + + /// Returns whether the pointer is properly aligned for `T`. + /// + /// # Examples + /// + /// ``` + /// #![feature(pointer_is_aligned)] + /// use std::ptr::NonNull; + /// + /// // On some platforms, the alignment of i32 is less than 4. + /// #[repr(align(4))] + /// struct AlignedI32(i32); + /// + /// let data = AlignedI32(42); + /// let ptr = NonNull::::from(&data); + /// + /// assert!(ptr.is_aligned()); + /// assert!(!NonNull::new(ptr.as_ptr().wrapping_byte_add(1)).unwrap().is_aligned()); + /// ``` + /// + /// # At compiletime + /// **Note: Alignment at compiletime is experimental and subject to change. See the + /// [tracking issue] for details.** + /// + /// At compiletime, the compiler may not know where a value will end up in memory. + /// Calling this function on a pointer created from a reference at compiletime will only + /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer + /// is never aligned if cast to a type with a stricter alignment than the reference's + /// underlying allocation. + /// + /// ``` + /// #![feature(pointer_is_aligned)] + /// #![feature(const_pointer_is_aligned)] + /// #![feature(non_null_convenience)] + /// #![feature(const_option)] + /// #![feature(const_nonnull_new)] + /// use std::ptr::NonNull; + /// + /// // On some platforms, the alignment of primitives is less than their size. + /// #[repr(align(4))] + /// struct AlignedI32(i32); + /// #[repr(align(8))] + /// struct AlignedI64(i64); + /// + /// const _: () = { + /// let data = [AlignedI32(42), AlignedI32(42)]; + /// let ptr = NonNull::::new(&data[0] as *const _ as *mut _).unwrap(); + /// assert!(ptr.is_aligned()); + /// + /// // At runtime either `ptr1` or `ptr2` would be aligned, but at compiletime neither is aligned. + /// let ptr1 = ptr.cast::(); + /// let ptr2 = unsafe { ptr.add(1).cast::() }; + /// assert!(!ptr1.is_aligned()); + /// assert!(!ptr2.is_aligned()); + /// }; + /// ``` + /// + /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime + /// pointer is aligned, even if the compiletime pointer wasn't aligned. + /// + /// ``` + /// #![feature(pointer_is_aligned)] + /// #![feature(const_pointer_is_aligned)] + /// + /// // On some platforms, the alignment of primitives is less than their size. + /// #[repr(align(4))] + /// struct AlignedI32(i32); + /// #[repr(align(8))] + /// struct AlignedI64(i64); + /// + /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. + /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); + /// const _: () = assert!(!COMPTIME_PTR.cast::().is_aligned()); + /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).cast::().is_aligned()); + /// + /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. + /// let runtime_ptr = COMPTIME_PTR; + /// assert_ne!( + /// runtime_ptr.cast::().is_aligned(), + /// runtime_ptr.wrapping_add(1).cast::().is_aligned(), + /// ); + /// ``` + /// + /// If a pointer is created from a fixed address, this function behaves the same during + /// runtime and compiletime. + /// + /// ``` + /// #![feature(pointer_is_aligned)] + /// #![feature(const_pointer_is_aligned)] + /// #![feature(const_option)] + /// #![feature(const_nonnull_new)] + /// use std::ptr::NonNull; + /// + /// // On some platforms, the alignment of primitives is less than their size. + /// #[repr(align(4))] + /// struct AlignedI32(i32); + /// #[repr(align(8))] + /// struct AlignedI64(i64); + /// + /// const _: () = { + /// let ptr = NonNull::new(40 as *mut AlignedI32).unwrap(); + /// assert!(ptr.is_aligned()); + /// + /// // For pointers with a known address, runtime and compiletime behavior are identical. + /// let ptr1 = ptr.cast::(); + /// let ptr2 = NonNull::new(ptr.as_ptr().wrapping_add(1)).unwrap().cast::(); + /// assert!(ptr1.is_aligned()); + /// assert!(!ptr2.is_aligned()); + /// }; + /// ``` + /// + /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 + #[unstable(feature = "pointer_is_aligned", issue = "96284")] + #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] + #[must_use] + #[inline] + pub const fn is_aligned(self) -> bool + where + T: Sized, + { + self.pointer.is_aligned() + } + + /// Returns whether the pointer is aligned to `align`. + /// + /// For non-`Sized` pointees this operation considers only the data pointer, + /// ignoring the metadata. + /// + /// # Panics + /// + /// The function panics if `align` is not a power-of-two (this includes 0). + /// + /// # Examples + /// + /// ``` + /// #![feature(pointer_is_aligned)] + /// + /// // On some platforms, the alignment of i32 is less than 4. + /// #[repr(align(4))] + /// struct AlignedI32(i32); + /// + /// let data = AlignedI32(42); + /// let ptr = &data as *const AlignedI32; + /// + /// assert!(ptr.is_aligned_to(1)); + /// assert!(ptr.is_aligned_to(2)); + /// assert!(ptr.is_aligned_to(4)); + /// + /// assert!(ptr.wrapping_byte_add(2).is_aligned_to(2)); + /// assert!(!ptr.wrapping_byte_add(2).is_aligned_to(4)); + /// + /// assert_ne!(ptr.is_aligned_to(8), ptr.wrapping_add(1).is_aligned_to(8)); + /// ``` + /// + /// # At compiletime + /// **Note: Alignment at compiletime is experimental and subject to change. See the + /// [tracking issue] for details.** + /// + /// At compiletime, the compiler may not know where a value will end up in memory. + /// Calling this function on a pointer created from a reference at compiletime will only + /// return `true` if the pointer is guaranteed to be aligned. This means that the pointer + /// cannot be stricter aligned than the reference's underlying allocation. + /// + /// ``` + /// #![feature(pointer_is_aligned)] + /// #![feature(const_pointer_is_aligned)] + /// + /// // On some platforms, the alignment of i32 is less than 4. + /// #[repr(align(4))] + /// struct AlignedI32(i32); + /// + /// const _: () = { + /// let data = AlignedI32(42); + /// let ptr = &data as *const AlignedI32; + /// + /// assert!(ptr.is_aligned_to(1)); + /// assert!(ptr.is_aligned_to(2)); + /// assert!(ptr.is_aligned_to(4)); + /// + /// // At compiletime, we know for sure that the pointer isn't aligned to 8. + /// assert!(!ptr.is_aligned_to(8)); + /// assert!(!ptr.wrapping_add(1).is_aligned_to(8)); + /// }; + /// ``` + /// + /// Due to this behavior, it is possible that a runtime pointer derived from a compiletime + /// pointer is aligned, even if the compiletime pointer wasn't aligned. + /// + /// ``` + /// #![feature(pointer_is_aligned)] + /// #![feature(const_pointer_is_aligned)] + /// + /// // On some platforms, the alignment of i32 is less than 4. + /// #[repr(align(4))] + /// struct AlignedI32(i32); + /// + /// // At compiletime, neither `COMPTIME_PTR` nor `COMPTIME_PTR + 1` is aligned. + /// const COMPTIME_PTR: *const AlignedI32 = &AlignedI32(42); + /// const _: () = assert!(!COMPTIME_PTR.is_aligned_to(8)); + /// const _: () = assert!(!COMPTIME_PTR.wrapping_add(1).is_aligned_to(8)); + /// + /// // At runtime, either `runtime_ptr` or `runtime_ptr + 1` is aligned. + /// let runtime_ptr = COMPTIME_PTR; + /// assert_ne!( + /// runtime_ptr.is_aligned_to(8), + /// runtime_ptr.wrapping_add(1).is_aligned_to(8), + /// ); + /// ``` + /// + /// If a pointer is created from a fixed address, this function behaves the same during + /// runtime and compiletime. + /// + /// ``` + /// #![feature(pointer_is_aligned)] + /// #![feature(const_pointer_is_aligned)] + /// + /// const _: () = { + /// let ptr = 40 as *const u8; + /// assert!(ptr.is_aligned_to(1)); + /// assert!(ptr.is_aligned_to(2)); + /// assert!(ptr.is_aligned_to(4)); + /// assert!(ptr.is_aligned_to(8)); + /// assert!(!ptr.is_aligned_to(16)); + /// }; + /// ``` + /// + /// [tracking issue]: https://github.com/rust-lang/rust/issues/104203 + #[unstable(feature = "pointer_is_aligned", issue = "96284")] + #[rustc_const_unstable(feature = "const_pointer_is_aligned", issue = "104203")] + #[must_use] + #[inline] + pub const fn is_aligned_to(self, align: usize) -> bool { + self.pointer.is_aligned_to(align) + } } impl NonNull<[T]> { From d920dd8d38517383d8154e2936864e16b6c3b729 Mon Sep 17 00:00:00 2001 From: Mark Rousskov Date: Sun, 26 Nov 2023 08:39:57 -0500 Subject: [PATCH 92/93] Remove Upvar duplication This cuts out an extra allocation and copying over from the already cached closure capture information. --- .../rustc_borrowck/src/diagnostics/mod.rs | 6 +-- .../src/diagnostics/move_errors.rs | 4 +- .../src/diagnostics/mutability_errors.rs | 5 +-- .../src/diagnostics/region_errors.rs | 2 +- .../src/diagnostics/var_name.rs | 9 ++--- compiler/rustc_borrowck/src/lib.rs | 37 +++++-------------- compiler/rustc_borrowck/src/nll.rs | 4 +- compiler/rustc_borrowck/src/path_utils.rs | 5 +-- compiler/rustc_borrowck/src/type_check/mod.rs | 6 +-- compiler/rustc_middle/src/ty/closure.rs | 7 ++++ 10 files changed, 35 insertions(+), 50 deletions(-) diff --git a/compiler/rustc_borrowck/src/diagnostics/mod.rs b/compiler/rustc_borrowck/src/diagnostics/mod.rs index fca3d6959355..cb3911450615 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mod.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mod.rs @@ -217,9 +217,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { projection: place.projection.split_at(index + 1).0, }) { let var_index = field.index(); - buf = self.upvars[var_index].place.to_string(self.infcx.tcx); + buf = self.upvars[var_index].to_string(self.infcx.tcx); ok = Ok(()); - if !self.upvars[var_index].by_ref { + if !self.upvars[var_index].is_by_ref() { buf.insert(0, '*'); } } else { @@ -250,7 +250,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { local, projection: place.projection.split_at(index + 1).0, }) { - buf = self.upvars[field.index()].place.to_string(self.infcx.tcx); + buf = self.upvars[field.index()].to_string(self.infcx.tcx); ok = Ok(()); } else { let field_name = self.describe_field( diff --git a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs index 86b761eadf5e..43487b85a7b3 100644 --- a/compiler/rustc_borrowck/src/diagnostics/move_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/move_errors.rs @@ -363,8 +363,8 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { format!("captured variable in an `{closure_kind}` closure"); let upvar = &self.upvars[upvar_field.unwrap().index()]; - let upvar_hir_id = upvar.place.get_root_variable(); - let upvar_name = upvar.place.to_string(self.infcx.tcx); + let upvar_hir_id = upvar.get_root_variable(); + let upvar_name = upvar.to_string(self.infcx.tcx); let upvar_span = self.infcx.tcx.hir().span(upvar_hir_id); let place_name = self.describe_any_place(move_place.as_ref()); diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index dde46eef6a0d..fd7939ac6acc 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -66,7 +66,6 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { )); let imm_borrow_derefed = self.upvars[upvar_index.index()] - .place .place .deref_tys() .any(|ty| matches!(ty.kind(), ty::Ref(.., hir::Mutability::Not))); @@ -85,7 +84,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { if self.is_upvar_field_projection(access_place.as_ref()).is_some() { reason = ", as it is not declared as mutable".to_string(); } else { - let name = self.upvars[upvar_index.index()].place.to_string(self.infcx.tcx); + let name = self.upvars[upvar_index.index()].to_string(self.infcx.tcx); reason = format!(", as `{name}` is not declared as mutable"); } } @@ -388,7 +387,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { Place::ty_from(local, proj_base, self.body, self.infcx.tcx).ty )); - let captured_place = &self.upvars[upvar_index.index()].place; + let captured_place = self.upvars[upvar_index.index()]; err.span_label(span, format!("cannot {act}")); diff --git a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs index 759d8ef30b1e..be500442611d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/region_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/region_errors.rs @@ -605,7 +605,7 @@ impl<'a, 'tcx> MirBorrowckCtxt<'a, 'tcx> { }; let captured_place = &self.upvars[upvar_field.index()].place; - let defined_hir = match captured_place.place.base { + let defined_hir = match captured_place.base { PlaceBase::Local(hirid) => Some(hirid), PlaceBase::Upvar(upvar) => Some(upvar.var_path.hir_id), _ => None, diff --git a/compiler/rustc_borrowck/src/diagnostics/var_name.rs b/compiler/rustc_borrowck/src/diagnostics/var_name.rs index 3a104c52431e..28e07f2a81ed 100644 --- a/compiler/rustc_borrowck/src/diagnostics/var_name.rs +++ b/compiler/rustc_borrowck/src/diagnostics/var_name.rs @@ -2,10 +2,9 @@ #![deny(rustc::diagnostic_outside_of_impl)] use crate::region_infer::RegionInferenceContext; -use crate::Upvar; use rustc_index::IndexSlice; use rustc_middle::mir::{Body, Local}; -use rustc_middle::ty::{RegionVid, TyCtxt}; +use rustc_middle::ty::{self, RegionVid, TyCtxt}; use rustc_span::symbol::Symbol; use rustc_span::Span; @@ -15,7 +14,7 @@ impl<'tcx> RegionInferenceContext<'tcx> { tcx: TyCtxt<'tcx>, body: &Body<'tcx>, local_names: &IndexSlice>, - upvars: &[Upvar<'tcx>], + upvars: &[&ty::CapturedPlace<'tcx>], fr: RegionVid, ) -> Option<(Option, Span)> { debug!("get_var_name_and_span_for_region(fr={fr:?})"); @@ -66,10 +65,10 @@ impl<'tcx> RegionInferenceContext<'tcx> { pub(crate) fn get_upvar_name_and_span_for_region( &self, tcx: TyCtxt<'tcx>, - upvars: &[Upvar<'tcx>], + upvars: &[&ty::CapturedPlace<'tcx>], upvar_index: usize, ) -> (Symbol, Span) { - let upvar_hir_id = upvars[upvar_index].place.get_root_variable(); + let upvar_hir_id = upvars[upvar_index].get_root_variable(); debug!("get_upvar_name_and_span_for_region: upvar_hir_id={upvar_hir_id:?}"); let upvar_name = tcx.hir().name(upvar_hir_id); diff --git a/compiler/rustc_borrowck/src/lib.rs b/compiler/rustc_borrowck/src/lib.rs index 804060d00ed0..3586c2cfea6f 100644 --- a/compiler/rustc_borrowck/src/lib.rs +++ b/compiler/rustc_borrowck/src/lib.rs @@ -35,7 +35,7 @@ use rustc_middle::mir::tcx::PlaceTy; use rustc_middle::mir::*; use rustc_middle::query::Providers; use rustc_middle::traits::DefiningAnchor; -use rustc_middle::ty::{self, CapturedPlace, ParamEnv, RegionVid, TyCtxt}; +use rustc_middle::ty::{self, ParamEnv, RegionVid, TyCtxt}; use rustc_session::lint::builtin::UNUSED_MUT; use rustc_span::{Span, Symbol}; use rustc_target::abi::FieldIdx; @@ -100,15 +100,6 @@ use renumber::RegionCtxt; fluent_messages! { "../messages.ftl" } -// FIXME(eddyb) perhaps move this somewhere more centrally. -#[derive(Debug)] -struct Upvar<'tcx> { - place: CapturedPlace<'tcx>, - - /// If true, the capture is behind a reference. - by_ref: bool, -} - /// Associate some local constants with the `'tcx` lifetime struct TyCtxtConsts<'tcx>(TyCtxt<'tcx>); impl<'tcx> TyCtxtConsts<'tcx> { @@ -193,18 +184,6 @@ fn do_mir_borrowck<'tcx>( infcx.set_tainted_by_errors(e); errors.set_tainted_by_errors(e); } - let upvars: Vec<_> = tcx - .closure_captures(def) - .iter() - .map(|&captured_place| { - let capture = captured_place.info.capture_kind; - let by_ref = match capture { - ty::UpvarCapture::ByValue => false, - ty::UpvarCapture::ByRef(..) => true, - }; - Upvar { place: captured_place.clone(), by_ref } - }) - .collect(); // Replace all regions with fresh inference variables. This // requires first making our own copy of the MIR. This copy will @@ -254,7 +233,7 @@ fn do_mir_borrowck<'tcx>( &mut flow_inits, &mdpe.move_data, &borrow_set, - &upvars, + tcx.closure_captures(def), consumer_options, ); @@ -324,7 +303,7 @@ fn do_mir_borrowck<'tcx>( used_mut: Default::default(), used_mut_upvars: SmallVec::new(), borrow_set: Rc::clone(&borrow_set), - upvars: Vec::new(), + upvars: &[], local_names: IndexVec::from_elem(None, &promoted_body.local_decls), region_names: RefCell::default(), next_region_name: RefCell::new(1), @@ -365,7 +344,7 @@ fn do_mir_borrowck<'tcx>( used_mut: Default::default(), used_mut_upvars: SmallVec::new(), borrow_set: Rc::clone(&borrow_set), - upvars, + upvars: tcx.closure_captures(def), local_names, region_names: RefCell::default(), next_region_name: RefCell::new(1), @@ -584,7 +563,7 @@ struct MirBorrowckCtxt<'cx, 'tcx> { borrow_set: Rc>, /// Information about upvars not necessarily preserved in types or MIR - upvars: Vec>, + upvars: &'tcx [&'tcx ty::CapturedPlace<'tcx>], /// Names of local (user) variables (extracted from `var_debug_info`). local_names: IndexVec>, @@ -2294,7 +2273,9 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { // unique path to the `&mut` hir::Mutability::Mut => { let mode = match self.is_upvar_field_projection(place) { - Some(field) if self.upvars[field.index()].by_ref => { + Some(field) + if self.upvars[field.index()].is_by_ref() => + { is_local_mutation_allowed } _ => LocalMutationIsAllowed::Yes, @@ -2342,7 +2323,7 @@ impl<'cx, 'tcx> MirBorrowckCtxt<'cx, 'tcx> { place={:?}, place_base={:?}", upvar, is_local_mutation_allowed, place, place_base ); - match (upvar.place.mutability, is_local_mutation_allowed) { + match (upvar.mutability, is_local_mutation_allowed) { ( Mutability::Not, LocalMutationIsAllowed::No diff --git a/compiler/rustc_borrowck/src/nll.rs b/compiler/rustc_borrowck/src/nll.rs index 08db3a62ece9..480358ef9972 100644 --- a/compiler/rustc_borrowck/src/nll.rs +++ b/compiler/rustc_borrowck/src/nll.rs @@ -37,7 +37,7 @@ use crate::{ renumber, type_check::{self, MirTypeckRegionConstraints, MirTypeckResults}, universal_regions::UniversalRegions, - BorrowckInferCtxt, Upvar, + BorrowckInferCtxt, }; pub type PoloniusOutput = Output; @@ -166,7 +166,7 @@ pub(crate) fn compute_regions<'cx, 'tcx>( flow_inits: &mut ResultsCursor<'cx, 'tcx, MaybeInitializedPlaces<'cx, 'tcx>>, move_data: &MoveData<'tcx>, borrow_set: &BorrowSet<'tcx>, - upvars: &[Upvar<'tcx>], + upvars: &[&ty::CapturedPlace<'tcx>], consumer_options: Option, ) -> NllOutput<'tcx> { let is_polonius_legacy_enabled = infcx.tcx.sess.opts.unstable_opts.polonius.is_legacy_enabled(); diff --git a/compiler/rustc_borrowck/src/path_utils.rs b/compiler/rustc_borrowck/src/path_utils.rs index 51e318f08543..2d997dfadf00 100644 --- a/compiler/rustc_borrowck/src/path_utils.rs +++ b/compiler/rustc_borrowck/src/path_utils.rs @@ -4,7 +4,6 @@ use crate::borrow_set::{BorrowData, BorrowSet, TwoPhaseActivation}; use crate::places_conflict; use crate::AccessDepth; use crate::BorrowIndex; -use crate::Upvar; use rustc_data_structures::graph::dominators::Dominators; use rustc_middle::mir::BorrowKind; use rustc_middle::mir::{BasicBlock, Body, Location, Place, PlaceRef, ProjectionElem}; @@ -150,7 +149,7 @@ pub(super) fn borrow_of_local_data(place: Place<'_>) -> bool { /// of a closure type. pub(crate) fn is_upvar_field_projection<'tcx>( tcx: TyCtxt<'tcx>, - upvars: &[Upvar<'tcx>], + upvars: &[&rustc_middle::ty::CapturedPlace<'tcx>], place_ref: PlaceRef<'tcx>, body: &Body<'tcx>, ) -> Option { @@ -166,7 +165,7 @@ pub(crate) fn is_upvar_field_projection<'tcx>( Some((place_base, ProjectionElem::Field(field, _ty))) => { let base_ty = place_base.ty(body, tcx).ty; if (base_ty.is_closure() || base_ty.is_coroutine()) - && (!by_ref || upvars[field.index()].by_ref) + && (!by_ref || upvars[field.index()].is_by_ref()) { Some(field) } else { diff --git a/compiler/rustc_borrowck/src/type_check/mod.rs b/compiler/rustc_borrowck/src/type_check/mod.rs index fdc710c4b4f3..5e9e93e91a09 100644 --- a/compiler/rustc_borrowck/src/type_check/mod.rs +++ b/compiler/rustc_borrowck/src/type_check/mod.rs @@ -68,7 +68,7 @@ use crate::{ region_infer::TypeTest, type_check::free_region_relations::{CreateResult, UniversalRegionRelations}, universal_regions::{DefiningTy, UniversalRegions}, - BorrowckInferCtxt, Upvar, + BorrowckInferCtxt, }; macro_rules! span_mirbug { @@ -138,7 +138,7 @@ pub(crate) fn type_check<'mir, 'tcx>( flow_inits: &mut ResultsCursor<'mir, 'tcx, MaybeInitializedPlaces<'mir, 'tcx>>, move_data: &MoveData<'tcx>, elements: &Rc, - upvars: &[Upvar<'tcx>], + upvars: &[&ty::CapturedPlace<'tcx>], use_polonius: bool, ) -> MirTypeckResults<'tcx> { let implicit_region_bound = ty::Region::new_var(infcx.tcx, universal_regions.fr_fn_body); @@ -857,7 +857,7 @@ struct BorrowCheckContext<'a, 'tcx> { all_facts: &'a mut Option, borrow_set: &'a BorrowSet<'tcx>, pub(crate) constraints: &'a mut MirTypeckRegionConstraints<'tcx>, - upvars: &'a [Upvar<'tcx>], + upvars: &'a [&'a ty::CapturedPlace<'tcx>], /// The set of loans that are live at a given point in the CFG, filled in by `liveness::trace`, /// when using `-Zpolonius=next`. diff --git a/compiler/rustc_middle/src/ty/closure.rs b/compiler/rustc_middle/src/ty/closure.rs index 74bdd07a1c94..c5ad3a073c08 100644 --- a/compiler/rustc_middle/src/ty/closure.rs +++ b/compiler/rustc_middle/src/ty/closure.rs @@ -247,6 +247,13 @@ impl<'tcx> CapturedPlace<'tcx> { .span } } + + pub fn is_by_ref(&self) -> bool { + match self.info.capture_kind { + ty::UpvarCapture::ByValue => false, + ty::UpvarCapture::ByRef(..) => true, + } + } } #[derive(Copy, Clone, Debug, HashStable)] From c751bfa015ab9e99f3c7845cebf04eb543648042 Mon Sep 17 00:00:00 2001 From: r0cky Date: Sun, 26 Nov 2023 14:24:38 +0800 Subject: [PATCH 93/93] Add proper cfgs --- library/alloc/src/alloc.rs | 3 +++ library/alloc/src/collections/mod.rs | 1 + library/alloc/src/rc.rs | 1 + library/alloc/src/sync.rs | 1 + library/alloc/src/vec/mod.rs | 5 +++++ 5 files changed, 11 insertions(+) diff --git a/library/alloc/src/alloc.rs b/library/alloc/src/alloc.rs index 2499f1053d86..1663aa84921c 100644 --- a/library/alloc/src/alloc.rs +++ b/library/alloc/src/alloc.rs @@ -423,12 +423,14 @@ pub mod __alloc_error_handler { } } +#[cfg(not(no_global_oom_handling))] /// Specialize clones into pre-allocated, uninitialized memory. /// Used by `Box::clone` and `Rc`/`Arc::make_mut`. pub(crate) trait WriteCloneIntoRaw: Sized { unsafe fn write_clone_into_raw(&self, target: *mut Self); } +#[cfg(not(no_global_oom_handling))] impl WriteCloneIntoRaw for T { #[inline] default unsafe fn write_clone_into_raw(&self, target: *mut Self) { @@ -438,6 +440,7 @@ impl WriteCloneIntoRaw for T { } } +#[cfg(not(no_global_oom_handling))] impl WriteCloneIntoRaw for T { #[inline] unsafe fn write_clone_into_raw(&self, target: *mut Self) { diff --git a/library/alloc/src/collections/mod.rs b/library/alloc/src/collections/mod.rs index 3e0b0f735508..705b81535c27 100644 --- a/library/alloc/src/collections/mod.rs +++ b/library/alloc/src/collections/mod.rs @@ -148,6 +148,7 @@ impl Display for TryReserveError { /// An intermediate trait for specialization of `Extend`. #[doc(hidden)] +#[cfg(not(no_global_oom_handling))] trait SpecExtend { /// Extends `self` with the contents of the given iterator. fn spec_extend(&mut self, iter: I); diff --git a/library/alloc/src/rc.rs b/library/alloc/src/rc.rs index dd7876bed769..98983e670d0f 100644 --- a/library/alloc/src/rc.rs +++ b/library/alloc/src/rc.rs @@ -2023,6 +2023,7 @@ impl Rc<[T], A> { } } +#[cfg(not(no_global_oom_handling))] /// Specialization trait used for `From<&[T]>`. trait RcFromSlice { fn from_slice(slice: &[T]) -> Self; diff --git a/library/alloc/src/sync.rs b/library/alloc/src/sync.rs index 351e6c1a4b3d..da0abdc97466 100644 --- a/library/alloc/src/sync.rs +++ b/library/alloc/src/sync.rs @@ -3503,6 +3503,7 @@ impl FromIterator for Arc<[T]> { } } +#[cfg(not(no_global_oom_handling))] /// Specialization trait used for collecting into `Arc<[T]>`. trait ToArcSlice: Iterator + Sized { fn to_arc_slice(self) -> Arc<[T]>; diff --git a/library/alloc/src/vec/mod.rs b/library/alloc/src/vec/mod.rs index ea7d6f6f4a64..bcf4163e39c4 100644 --- a/library/alloc/src/vec/mod.rs +++ b/library/alloc/src/vec/mod.rs @@ -58,6 +58,7 @@ use core::cmp; use core::cmp::Ordering; use core::fmt; use core::hash::{Hash, Hasher}; +#[cfg(not(no_global_oom_handling))] use core::iter; use core::marker::PhantomData; use core::mem::{self, ManuallyDrop, MaybeUninit, SizedTypeProperties}; @@ -101,6 +102,7 @@ mod into_iter; #[cfg(not(no_global_oom_handling))] use self::is_zero::IsZero; +#[cfg(not(no_global_oom_handling))] mod is_zero; #[cfg(not(no_global_oom_handling))] @@ -2599,6 +2601,7 @@ pub fn from_elem_in(elem: T, n: usize, alloc: A) -> Vec< ::from_elem(elem, n, alloc) } +#[cfg(not(no_global_oom_handling))] trait ExtendFromWithinSpec { /// # Safety /// @@ -2607,6 +2610,7 @@ trait ExtendFromWithinSpec { unsafe fn spec_extend_from_within(&mut self, src: Range); } +#[cfg(not(no_global_oom_handling))] impl ExtendFromWithinSpec for Vec { default unsafe fn spec_extend_from_within(&mut self, src: Range) { // SAFETY: @@ -2626,6 +2630,7 @@ impl ExtendFromWithinSpec for Vec { } } +#[cfg(not(no_global_oom_handling))] impl ExtendFromWithinSpec for Vec { unsafe fn spec_extend_from_within(&mut self, src: Range) { let count = src.len();