From 8f9cd3d1e820eb114c32627cc34f3897cda7903e Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 3 Oct 2023 15:17:52 +0200 Subject: [PATCH 01/52] Rework range splitting api --- .../src/thir/pattern/deconstruct_pat.rs | 202 ++++++++---------- 1 file changed, 90 insertions(+), 112 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 3ee4befa12189..d63190985a313 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -39,7 +39,7 @@ //! //! 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 [`SplitWildcard`]; for integer ranges, see [`SplitIntRange`]; for slices, see +//! wildcards, see [`SplitWildcard`]; for integer ranges, see [`IntRange::split`]; for slices, see //! [`SplitVarLenSlice`]. use std::cell::Cell; @@ -186,6 +186,93 @@ impl IntRange { (lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton() } + /// See `Constructor::is_covered_by` + fn is_covered_by(&self, other: &Self) -> bool { + if self.intersection(other).is_some() { + // Constructor splitting should ensure that all intersections we encounter are actually + // inclusions. + assert!(self.is_subrange(other)); + true + } else { + false + } + } + + /// Partition a range of integers into disjoint subranges. This does constructor splitting for + /// integer ranges as explained at the top of the file. + /// + /// This returns an output that covers `self`. The output is split so that the only + /// intersections between an output range and a column range are inclusions. No output range + /// straddles the boundary of one of the inputs. + /// + /// The following input: + /// ```text + /// |-------------------------| // `self` + /// |------| |----------| |----| + /// |-------| |-------| + /// ``` + /// would be iterated over as follows: + /// ```text + /// ||---|--||-|---|---|---|--| + /// ``` + fn split( + &self, + column_ranges: impl Iterator, + ) -> impl Iterator { + /// Represents a boundary between 2 integers. Because the intervals spanning boundaries must be + /// able to cover every integer, we need to be able to represent 2^128 + 1 such boundaries. + #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] + enum IntBoundary { + JustBefore(u128), + AfterMax, + } + + fn unpack_intrange(range: IntRange) -> [IntBoundary; 2] { + use IntBoundary::*; + let (lo, hi) = range.boundaries(); + let lo = JustBefore(lo); + let hi = match hi.checked_add(1) { + Some(m) => JustBefore(m), + None => AfterMax, + }; + [lo, hi] + } + + // The boundaries of ranges in `column_ranges` intersected with `self`. + let mut boundaries: Vec = column_ranges + .filter_map(|r| self.intersection(&r)) + .map(unpack_intrange) + .flat_map(|[lo, hi]| [lo, hi]) + .collect(); + boundaries.sort_unstable(); + + let [self_start, self_end] = unpack_intrange(self.clone()); + // Gather pairs of adjacent boundaries. + let mut prev_bdy = self_start; + boundaries + .into_iter() + // End with the end of the range. + .chain(once(self_end)) + // List pairs of adjacent boundaries. + .map(move |bdy| { + let ret = (prev_bdy, bdy); + prev_bdy = bdy; + ret + }) + // Skip duplicates. + .filter(|&(prev_bdy, bdy)| prev_bdy != bdy) + // Convert back to ranges. + .map(move |(prev_bdy, bdy)| { + use IntBoundary::*; + let range = match (prev_bdy, bdy) { + (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1), + (JustBefore(n), AfterMax) => n..=u128::MAX, + _ => unreachable!(), // Ruled out by the sorting and filtering we did + }; + IntRange { range } + }) + } + /// Only used for displaying the range properly. fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { let (lo, hi) = self.boundaries(); @@ -254,18 +341,6 @@ impl IntRange { ); } } - - /// See `Constructor::is_covered_by` - fn is_covered_by(&self, other: &Self) -> bool { - if self.intersection(other).is_some() { - // Constructor splitting should ensure that all intersections we encounter are actually - // inclusions. - assert!(self.is_subrange(other)); - true - } else { - false - } - } } /// Note: this is often not what we want: e.g. `false` is converted into the range `0..=0` and @@ -279,101 +354,6 @@ impl fmt::Debug for IntRange { } } -/// Represents a border between 2 integers. Because the intervals spanning borders must be able to -/// cover every integer, we need to be able to represent 2^128 + 1 such borders. -#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] -enum IntBorder { - JustBefore(u128), - AfterMax, -} - -/// A range of integers that is partitioned into disjoint subranges. This does constructor -/// splitting for integer ranges as explained at the top of the file. -/// -/// This is fed multiple ranges, and returns an output that covers the input, but is split so that -/// the only intersections between an output range and a seen range are inclusions. No output range -/// straddles the boundary of one of the inputs. -/// -/// The following input: -/// ```text -/// |-------------------------| // `self` -/// |------| |----------| |----| -/// |-------| |-------| -/// ``` -/// would be iterated over as follows: -/// ```text -/// ||---|--||-|---|---|---|--| -/// ``` -#[derive(Debug, Clone)] -struct SplitIntRange { - /// The range we are splitting - range: IntRange, - /// The borders of ranges we have seen. They are all contained within `range`. This is kept - /// sorted. - borders: Vec, -} - -impl SplitIntRange { - fn new(range: IntRange) -> Self { - SplitIntRange { range, borders: Vec::new() } - } - - /// Internal use - fn to_borders(r: IntRange) -> [IntBorder; 2] { - use IntBorder::*; - let (lo, hi) = r.boundaries(); - let lo = JustBefore(lo); - let hi = match hi.checked_add(1) { - Some(m) => JustBefore(m), - None => AfterMax, - }; - [lo, hi] - } - - /// Add ranges relative to which we split. - fn split(&mut self, ranges: impl Iterator) { - let this_range = &self.range; - let included_ranges = ranges.filter_map(|r| this_range.intersection(&r)); - let included_borders = included_ranges.flat_map(|r| { - let borders = Self::to_borders(r); - once(borders[0]).chain(once(borders[1])) - }); - self.borders.extend(included_borders); - self.borders.sort_unstable(); - } - - /// Iterate over the contained ranges. - fn iter(&self) -> impl Iterator + Captures<'_> { - use IntBorder::*; - - let self_range = Self::to_borders(self.range.clone()); - // Start with the start of the range. - let mut prev_border = self_range[0]; - self.borders - .iter() - .copied() - // End with the end of the range. - .chain(once(self_range[1])) - // List pairs of adjacent borders. - .map(move |border| { - let ret = (prev_border, border); - prev_border = border; - ret - }) - // Skip duplicates. - .filter(|(prev_border, border)| prev_border != border) - // Finally, convert to ranges. - .map(move |(prev_border, border)| { - let range = match (prev_border, border) { - (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1), - (JustBefore(n), AfterMax) => n..=u128::MAX, - _ => unreachable!(), // Ruled out by the sorting and filtering we did - }; - IntRange { range } - }) - } -} - #[derive(Copy, Clone, Debug, PartialEq, Eq)] enum SliceKind { /// Patterns of length `n` (`[x, y]`). @@ -733,10 +713,8 @@ impl<'tcx> Constructor<'tcx> { // Fast-track if the range is trivial. In particular, we don't do the overlapping // ranges check. IntRange(ctor_range) if !ctor_range.is_singleton() => { - let mut split_range = SplitIntRange::new(ctor_range.clone()); - let int_ranges = ctors.filter_map(|ctor| ctor.as_int_range()); - split_range.split(int_ranges.cloned()); - split_range.iter().map(IntRange).collect() + let int_ranges = ctors.filter_map(|ctor| ctor.as_int_range()).cloned(); + ctor_range.split(int_ranges).map(IntRange).collect() } &Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => { let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len); From 590edee3209906b3906f09bad029586b0a15e29f Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 3 Oct 2023 14:38:40 +0200 Subject: [PATCH 02/52] Rework slice splitting api --- .../src/thir/pattern/deconstruct_pat.rs | 253 +++++++++--------- 1 file changed, 120 insertions(+), 133 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 d63190985a313..6755e665bba1d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -40,7 +40,7 @@ //! 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 [`SplitWildcard`]; for integer ranges, see [`IntRange::split`]; for slices, see -//! [`SplitVarLenSlice`]. +//! [`Slice::split`]. use std::cell::Cell; use std::cmp::{self, max, min, Ordering}; @@ -410,141 +410,130 @@ impl Slice { fn is_covered_by(self, other: Self) -> bool { other.kind.covers_length(self.arity()) } -} -/// This computes constructor splitting for variable-length slices, as explained at the top of the -/// file. -/// -/// A slice pattern `[x, .., y]` behaves like the infinite or-pattern `[x, y] | [x, _, y] | [x, _, -/// _, y] | ...`. The corresponding value constructors are fixed-length array constructors above a -/// given minimum length. We obviously can't list this infinitude of constructors. Thankfully, -/// it turns out that for each finite set of slice patterns, all sufficiently large array lengths -/// are equivalent. -/// -/// Let's look at an example, where we are trying to split the last pattern: -/// ``` -/// # fn foo(x: &[bool]) { -/// match x { -/// [true, true, ..] => {} -/// [.., false, false] => {} -/// [..] => {} -/// } -/// # } -/// ``` -/// Here are the results of specialization for the first few lengths: -/// ``` -/// # fn foo(x: &[bool]) { match x { -/// // length 0 -/// [] => {} -/// // length 1 -/// [_] => {} -/// // length 2 -/// [true, true] => {} -/// [false, false] => {} -/// [_, _] => {} -/// // length 3 -/// [true, true, _ ] => {} -/// [_, false, false] => {} -/// [_, _, _ ] => {} -/// // length 4 -/// [true, true, _, _ ] => {} -/// [_, _, false, false] => {} -/// [_, _, _, _ ] => {} -/// // length 5 -/// [true, true, _, _, _ ] => {} -/// [_, _, _, false, false] => {} -/// [_, _, _, _, _ ] => {} -/// # _ => {} -/// # }} -/// ``` -/// -/// If we went above length 5, we would simply be inserting more columns full of wildcards in the -/// middle. This means that the set of witnesses for length `l >= 5` if equivalent to the set for -/// any other `l' >= 5`: simply add or remove wildcards in the middle to convert between them. -/// -/// This applies to any set of slice patterns: there will be a length `L` above which all lengths -/// behave the same. This is exactly what we need for constructor splitting. Therefore a -/// variable-length slice can be split into a variable-length slice of minimal length `L`, and many -/// fixed-length slices of lengths `< L`. -/// -/// For each variable-length pattern `p` with a prefix of length `plₚ` and suffix of length `slₚ`, -/// only the first `plₚ` and the last `slₚ` elements are examined. Therefore, as long as `L` is -/// positive (to avoid concerns about empty types), all elements after the maximum prefix length -/// and before the maximum suffix length are not examined by any variable-length pattern, and -/// therefore can be added/removed without affecting them - creating equivalent patterns from any -/// sufficiently-large length. -/// -/// Of course, if fixed-length patterns exist, we must be sure that our length is large enough to -/// miss them all, so we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))` -/// -/// `max_slice` below will be made to have arity `L`. -#[derive(Debug)] -struct SplitVarLenSlice { - /// If the type is an array, this is its size. - array_len: Option, - /// The arity of the input slice. - arity: usize, - /// The smallest slice bigger than any slice seen. `max_slice.arity()` is the length `L` - /// described above. - max_slice: SliceKind, -} - -impl SplitVarLenSlice { - fn new(prefix: usize, suffix: usize, array_len: Option) -> Self { - SplitVarLenSlice { array_len, arity: prefix + suffix, max_slice: VarLen(prefix, suffix) } - } - - /// Pass a set of slices relative to which to split this one. - fn split(&mut self, slices: impl Iterator) { - let VarLen(max_prefix_len, max_suffix_len) = &mut self.max_slice else { - // No need to split - return; - }; - // We grow `self.max_slice` to be larger than all slices encountered, as described above. - // For diagnostics, we keep the prefix and suffix lengths separate, but grow them so that - // `L = max_prefix_len + max_suffix_len`. - let mut max_fixed_len = 0; - for slice in slices { - match slice { - FixedLen(len) => { - max_fixed_len = cmp::max(max_fixed_len, len); + /// This computes constructor splitting for variable-length slices, as explained at the top of + /// the file. + /// + /// A slice pattern `[x, .., y]` behaves like the infinite or-pattern `[x, y] | [x, _, y] | [x, + /// _, _, y] | etc`. The corresponding value constructors are fixed-length array constructors of + /// corresponding lengths. We obviously can't list this infinitude of constructors. + /// Thankfully, it turns out that for each finite set of slice patterns, all sufficiently large + /// array lengths are equivalent. + /// + /// Let's look at an example, where we are trying to split the last pattern: + /// ``` + /// # fn foo(x: &[bool]) { + /// match x { + /// [true, true, ..] => {} + /// [.., false, false] => {} + /// [..] => {} // `self` + /// } + /// # } + /// ``` + /// Here are the results of specialization for the first few lengths: + /// ``` + /// # fn foo(x: &[bool]) { match x { + /// // length 0 + /// [] => {} + /// // length 1 + /// [_] => {} + /// // length 2 + /// [true, true] => {} + /// [false, false] => {} + /// [_, _] => {} + /// // length 3 + /// [true, true, _ ] => {} + /// [_, false, false] => {} + /// [_, _, _ ] => {} + /// // length 4 + /// [true, true, _, _ ] => {} + /// [_, _, false, false] => {} + /// [_, _, _, _ ] => {} + /// // length 5 + /// [true, true, _, _, _ ] => {} + /// [_, _, _, false, false] => {} + /// [_, _, _, _, _ ] => {} + /// # _ => {} + /// # }} + /// ``` + /// + /// We see that above length 4, we are simply inserting columns full of wildcards in the middle. + /// This means that specialization and witness computation with slices of length `l >= 4` will + /// give equivalent results independently of `l`. This applies to any set of slice patterns: + /// there will be a length `L` above which all lengths behave the same. This is exactly what we + /// need for constructor splitting. + /// + /// A variable-length slice pattern covers all lengths from its arity up to infinity. As we just + /// saw, we can split this in two: lengths below `L` are treated individually with a + /// fixed-length slice each; lengths above `L` are grouped into a single variable-length slice + /// constructor. + /// + /// For each variable-length slice pattern `p` with a prefix of length `plₚ` and suffix of + /// length `slₚ`, only the first `plₚ` and the last `slₚ` elements are examined. Therefore, as + /// long as `L` is positive (to avoid concerns about empty types), all elements after the + /// maximum prefix length and before the maximum suffix length are not examined by any + /// variable-length pattern, and therefore can be ignored. This gives us a way to compute `L`. + /// + /// Additionally, if fixed-length patterns exist, we must pick an `L` large enough to miss them, + /// so we can pick `L = max(max(FIXED_LEN)+1, max(PREFIX_LEN) + max(SUFFIX_LEN))`. + /// `max_slice` below will be made to have this arity `L`. + /// + /// If `self` is fixed-length, it is returned as-is. + fn split(self, column_slices: impl Iterator) -> impl Iterator { + // Range of lengths below `L`. + let smaller_lengths; + let mut max_slice = self.kind; + match &mut max_slice { + VarLen(max_prefix_len, max_suffix_len) => { + // We grow `max_slice` to be larger than all slices encountered, as described above. + // For diagnostics, we keep the prefix and suffix lengths separate, but grow them so that + // `L = max_prefix_len + max_suffix_len`. + let mut max_fixed_len = 0; + for slice in column_slices { + match slice.kind { + FixedLen(len) => { + max_fixed_len = cmp::max(max_fixed_len, len); + } + VarLen(prefix, suffix) => { + *max_prefix_len = cmp::max(*max_prefix_len, prefix); + *max_suffix_len = cmp::max(*max_suffix_len, suffix); + } + } } - VarLen(prefix, suffix) => { - *max_prefix_len = cmp::max(*max_prefix_len, prefix); - *max_suffix_len = cmp::max(*max_suffix_len, suffix); + // We want `L = max(L, max_fixed_len + 1)`, modulo the fact that we keep prefix and + // suffix separate. + if max_fixed_len + 1 >= *max_prefix_len + *max_suffix_len { + // The subtraction can't overflow thanks to the above check. + // The new `max_prefix_len` is larger than its previous value. + *max_prefix_len = max_fixed_len + 1 - *max_suffix_len; } - } - } - // We want `L = max(L, max_fixed_len + 1)`, modulo the fact that we keep prefix and - // suffix separate. - if max_fixed_len + 1 >= *max_prefix_len + *max_suffix_len { - // The subtraction can't overflow thanks to the above check. - // The new `max_prefix_len` is larger than its previous value. - *max_prefix_len = max_fixed_len + 1 - *max_suffix_len; - } - // We cap the arity of `max_slice` at the array size. - match self.array_len { - Some(len) if self.max_slice.arity() >= len => self.max_slice = FixedLen(len), - _ => {} - } - } + // We cap the arity of `max_slice` at the array size. + match self.array_len { + Some(len) if max_slice.arity() >= len => max_slice = FixedLen(len), + _ => {} + } - /// Iterate over the partition of this slice. - fn iter(&self) -> impl Iterator + Captures<'_> { - let smaller_lengths = match self.array_len { - // The only admissible fixed-length slice is one of the array size. Whether `max_slice` - // is fixed-length or variable-length, it will be the only relevant slice to output - // here. - Some(_) => 0..0, // empty range - // We cover all arities in the range `(self.arity..infinity)`. We split that range into - // two: lengths smaller than `max_slice.arity()` are treated independently as - // fixed-lengths slices, and lengths above are captured by `max_slice`. - None => self.arity..self.max_slice.arity(), + smaller_lengths = match self.array_len { + // The only admissible fixed-length slice is one of the array size. Whether `max_slice` + // is fixed-length or variable-length, it will be the only relevant slice to output + // here. + Some(_) => 0..0, // empty range + // We need to cover all arities in the range `(arity..infinity)`. We split that + // range into two: lengths smaller than `max_slice.arity()` are treated + // independently as fixed-lengths slices, and lengths above are captured by + // `max_slice`. + None => self.arity()..max_slice.arity(), + }; + } + FixedLen(_) => { + // No need to split. + smaller_lengths = 0..0; + } }; smaller_lengths .map(FixedLen) - .chain(once(self.max_slice)) + .chain(once(max_slice)) .map(move |kind| Slice::new(self.array_len, kind)) } } @@ -716,11 +705,9 @@ impl<'tcx> Constructor<'tcx> { let int_ranges = ctors.filter_map(|ctor| ctor.as_int_range()).cloned(); ctor_range.split(int_ranges).map(IntRange).collect() } - &Slice(Slice { kind: VarLen(self_prefix, self_suffix), array_len }) => { - let mut split_self = SplitVarLenSlice::new(self_prefix, self_suffix, array_len); - let slices = ctors.filter_map(|c| c.as_slice()).map(|s| s.kind); - split_self.split(slices); - split_self.iter().map(Slice).collect() + &Slice(slice @ Slice { kind: VarLen(..), .. }) => { + let slices = ctors.filter_map(|c| c.as_slice()); + slice.split(slices).map(Slice).collect() } // Any other constructor can be used unchanged. _ => smallvec![self.clone()], From 429770a48eb7dcb11831d4670a25a01c698f704c Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 3 Oct 2023 16:21:40 +0200 Subject: [PATCH 03/52] Splitting ensures subrange comparison is all we need --- .../src/thir/pattern/deconstruct_pat.rs | 14 +------------- 1 file changed, 1 insertion(+), 13 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 6755e665bba1d..b4bc456987880 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -186,18 +186,6 @@ impl IntRange { (lo == other_hi || hi == other_lo) && !self.is_singleton() && !other.is_singleton() } - /// See `Constructor::is_covered_by` - fn is_covered_by(&self, other: &Self) -> bool { - if self.intersection(other).is_some() { - // Constructor splitting should ensure that all intersections we encounter are actually - // inclusions. - assert!(self.is_subrange(other)); - true - } else { - false - } - } - /// Partition a range of integers into disjoint subranges. This does constructor splitting for /// integer ranges as explained at the top of the file. /// @@ -730,7 +718,7 @@ impl<'tcx> Constructor<'tcx> { (Single, Single) => true, (Variant(self_id), Variant(other_id)) => self_id == other_id, - (IntRange(self_range), IntRange(other_range)) => self_range.is_covered_by(other_range), + (IntRange(self_range), IntRange(other_range)) => self_range.is_subrange(other_range), (F32Range(self_from, self_to, self_end), F32Range(other_from, other_to, other_end)) => { self_from.ge(other_from) && match self_to.partial_cmp(other_to) { From c1800ef93fa44ac583c213632a315956b5b2f31b Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 3 Oct 2023 15:30:05 +0200 Subject: [PATCH 04/52] Replace SplitWildcard with a cleaner ConstructorSet abstraction --- .../src/thir/pattern/deconstruct_pat.rs | 622 +++++++++++------- .../src/thir/pattern/usefulness.rs | 130 ++-- 2 files changed, 434 insertions(+), 318 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 b4bc456987880..ab30f5109c77d 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -39,8 +39,8 @@ //! //! 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 [`SplitWildcard`]; for integer ranges, see [`IntRange::split`]; for slices, see -//! [`Slice::split`]. +//! wildcards, see [`Constructor::split`]; for integer ranges, see +//! [`IntRange::split`]; for slices, see [`Slice::split`]. use std::cell::Cell; use std::cmp::{self, max, min, Ordering}; @@ -52,6 +52,7 @@ use smallvec::{smallvec, SmallVec}; use rustc_apfloat::ieee::{DoubleS, IeeeFloat, SingleS}; use rustc_data_structures::captures::Captures; +use rustc_data_structures::fx::FxHashSet; use rustc_hir::{HirId, RangeEnd}; use rustc_index::Idx; use rustc_middle::middle::stability::EvalResult; @@ -86,6 +87,13 @@ fn expand_or_pat<'p, 'tcx>(pat: &'p Pat<'tcx>) -> Vec<&'p Pat<'tcx>> { pats } +/// Whether we have seen a constructor in the column or not. +#[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] +enum Presence { + Unseen, + Seen, +} + /// An inclusive interval, used for precise integer exhaustiveness checking. /// `IntRange`s always store a contiguous range. This means that values are /// encoded such that `0` encodes the minimum value for the integer, @@ -203,10 +211,12 @@ impl IntRange { /// ```text /// ||---|--||-|---|---|---|--| /// ``` + /// + /// Additionally, we track for each output range whether it is covered by one of the column ranges or not. fn split( &self, column_ranges: impl Iterator, - ) -> impl Iterator { + ) -> impl Iterator { /// Represents a boundary between 2 integers. Because the intervals spanning boundaries must be /// able to cover every integer, we need to be able to represent 2^128 + 1 such boundaries. #[derive(Debug, Clone, Copy, PartialEq, Eq, PartialOrd, Ord)] @@ -227,41 +237,57 @@ impl IntRange { } // The boundaries of ranges in `column_ranges` intersected with `self`. - let mut boundaries: Vec = column_ranges + // We do parenthesis matching for input ranges. A boundary counts as +1 if it starts + // a range and -1 if it ends it. When the count is > 0 between two boundaries, we + // are within an input range. + let mut boundaries: Vec<(IntBoundary, isize)> = column_ranges .filter_map(|r| self.intersection(&r)) .map(unpack_intrange) - .flat_map(|[lo, hi]| [lo, hi]) + .flat_map(|[lo, hi]| [(lo, 1), (hi, -1)]) .collect(); boundaries.sort_unstable(); + // Counter for parenthesis matching. + let mut paren_counter = 0isize; + let boundaries_with_paren_counts = boundaries + .into_iter() + // Accumulate parenthesis counts. + .map(move |(bdy, delta)| { + paren_counter += delta; + (bdy, paren_counter) + }); + let [self_start, self_end] = unpack_intrange(self.clone()); // Gather pairs of adjacent boundaries. let mut prev_bdy = self_start; - boundaries - .into_iter() - // End with the end of the range. - .chain(once(self_end)) + let mut prev_paren_count = 0; + boundaries_with_paren_counts + // End with the end of the range. The count is irrelevant. + .chain(once((self_end, 0))) // List pairs of adjacent boundaries. - .map(move |bdy| { - let ret = (prev_bdy, bdy); + .map(move |(bdy, paren_count)| { + let ret = (prev_bdy, prev_paren_count, bdy); prev_bdy = bdy; + prev_paren_count = paren_count; ret }) // Skip duplicates. - .filter(|&(prev_bdy, bdy)| prev_bdy != bdy) + .filter(|&(prev_bdy, _, bdy)| prev_bdy != bdy) // Convert back to ranges. - .map(move |(prev_bdy, bdy)| { + .map(move |(prev_bdy, paren_count, bdy)| { use IntBoundary::*; + use Presence::*; + let presence = if paren_count > 0 { Seen } else { Unseen }; let range = match (prev_bdy, bdy) { (JustBefore(n), JustBefore(m)) if n < m => n..=(m - 1), (JustBefore(n), AfterMax) => n..=u128::MAX, _ => unreachable!(), // Ruled out by the sorting and filtering we did }; - IntRange { range } + (presence, IntRange { range }) }) } - /// Only used for displaying the range properly. + /// Only used for displaying the range. fn to_pat<'tcx>(&self, tcx: TyCtxt<'tcx>, ty: Ty<'tcx>) -> Pat<'tcx> { let (lo, hi) = self.boundaries(); @@ -414,7 +440,7 @@ impl Slice { /// match x { /// [true, true, ..] => {} /// [.., false, false] => {} - /// [..] => {} // `self` + /// [..] => {} /// } /// # } /// ``` @@ -447,9 +473,9 @@ impl Slice { /// /// We see that above length 4, we are simply inserting columns full of wildcards in the middle. /// This means that specialization and witness computation with slices of length `l >= 4` will - /// give equivalent results independently of `l`. This applies to any set of slice patterns: - /// there will be a length `L` above which all lengths behave the same. This is exactly what we - /// need for constructor splitting. + /// give equivalent results regardless of `l`. This applies to any set of slice patterns: there + /// will be a length `L` above which all lengths behave the same. This is exactly what we need + /// for constructor splitting. /// /// A variable-length slice pattern covers all lengths from its arity up to infinity. As we just /// saw, we can split this in two: lengths below `L` are treated individually with a @@ -467,10 +493,18 @@ impl Slice { /// `max_slice` below will be made to have this arity `L`. /// /// If `self` is fixed-length, it is returned as-is. - fn split(self, column_slices: impl Iterator) -> impl Iterator { + /// + /// Additionally, we track for each output slice whether it is covered by one of the column slices or not. + fn split( + self, + column_slices: impl Iterator, + ) -> impl Iterator { // Range of lengths below `L`. let smaller_lengths; + let arity = self.arity(); let mut max_slice = self.kind; + let mut min_var_len = usize::MAX; + let mut seen_fixed_lens = FxHashSet::default(); match &mut max_slice { VarLen(max_prefix_len, max_suffix_len) => { // We grow `max_slice` to be larger than all slices encountered, as described above. @@ -481,10 +515,14 @@ impl Slice { match slice.kind { FixedLen(len) => { max_fixed_len = cmp::max(max_fixed_len, len); + if arity <= len { + seen_fixed_lens.insert(len); + } } VarLen(prefix, suffix) => { *max_prefix_len = cmp::max(*max_prefix_len, prefix); *max_suffix_len = cmp::max(*max_suffix_len, suffix); + min_var_len = cmp::min(min_var_len, prefix + suffix); } } } @@ -515,14 +553,32 @@ impl Slice { }; } FixedLen(_) => { - // No need to split. + // No need to split here. We only track presence. + for slice in column_slices { + match slice.kind { + FixedLen(len) => { + if len == arity { + seen_fixed_lens.insert(len); + } + } + VarLen(prefix, suffix) => { + min_var_len = cmp::min(min_var_len, prefix + suffix); + } + } + } smaller_lengths = 0..0; } }; - smaller_lengths - .map(FixedLen) - .chain(once(max_slice)) - .map(move |kind| Slice::new(self.array_len, kind)) + + smaller_lengths.map(FixedLen).chain(once(max_slice)).map(move |kind| { + let arity = kind.arity(); + let seen = if min_var_len <= arity || seen_fixed_lens.contains(&arity) { + Presence::Seen + } else { + Presence::Unseen + }; + (seen, Slice::new(self.array_len, kind)) + }) } } @@ -556,8 +612,8 @@ pub(super) enum Constructor<'tcx> { /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. NonExhaustive, - /// Stands for constructors that are not seen in the matrix, as explained in the documentation - /// for [`SplitWildcard`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns` + /// Stands for constructors that are not seen in the matrix, as explained in the code for + /// [`Constructor::split`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns` /// lint. Missing { nonexhaustive_enum_missing_real_variants: bool, @@ -577,13 +633,18 @@ impl<'tcx> Constructor<'tcx> { matches!(self, NonExhaustive) } + pub(super) fn as_variant(&self) -> Option { + match self { + Variant(i) => Some(*i), + _ => None, + } + } fn as_int_range(&self) -> Option<&IntRange> { match self { IntRange(range) => Some(range), _ => None, } } - fn as_slice(&self) -> Option { match self { Slice(slice) => Some(*slice), @@ -660,19 +721,19 @@ 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. + /// 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 wrt 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. + /// 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 and - /// diagnostics. Eg. for the `_` case, we ignore the constructors already present in the - /// matrix, unless all of them are. + /// 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>, @@ -683,19 +744,74 @@ impl<'tcx> Constructor<'tcx> { { match self { Wildcard => { - let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, ctors); - split_wildcard.into_ctors(pcx) + 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 { + nonexhaustive_enum_missing_real_variants: split_set + .nonexhaustive_enum_missing_real_variants, + } + }; + smallvec![ctor] + } else { + split_set.present + } } - // Fast-track if the range is trivial. In particular, we don't do the overlapping - // ranges check. - IntRange(ctor_range) if !ctor_range.is_singleton() => { - let int_ranges = ctors.filter_map(|ctor| ctor.as_int_range()).cloned(); - ctor_range.split(int_ranges).map(IntRange).collect() + // 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(slice @ Slice { kind: VarLen(..), .. }) => { - let slices = ctors.filter_map(|c| c.as_slice()); - slice.split(slices).map(Slice).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()], @@ -755,96 +871,112 @@ impl<'tcx> Constructor<'tcx> { ), } } +} - /// Faster version of `is_covered_by` when applied to many constructors. `used_ctors` is - /// assumed to be built from `matrix.head_ctors()` with wildcards and opaques filtered out, - /// and `self` is assumed to have been split from a wildcard. - fn is_covered_by_any<'p>( - &self, - pcx: &PatCtxt<'_, 'p, 'tcx>, - used_ctors: &[Constructor<'tcx>], - ) -> bool { - if used_ctors.is_empty() { - return false; - } - - // This must be kept in sync with `is_covered_by`. - match self { - // If `self` is `Single`, `used_ctors` cannot contain anything else than `Single`s. - Single => !used_ctors.is_empty(), - Variant(vid) => used_ctors.iter().any(|c| matches!(c, Variant(i) if i == vid)), - IntRange(range) => used_ctors - .iter() - .filter_map(|c| c.as_int_range()) - .any(|other| range.is_covered_by(other)), - Slice(slice) => used_ctors - .iter() - .filter_map(|c| c.as_slice()) - .any(|other| slice.is_covered_by(other)), - // This constructor is never covered by anything else - NonExhaustive => false, - Str(..) | F32Range(..) | F64Range(..) | Opaque | Missing { .. } | Wildcard | Or => { - span_bug!(pcx.span, "found unexpected ctor in all_ctors: {:?}", self) - } - } - } +/// Describes the set of all constructors for a type. +pub(super) enum ConstructorSet { + /// The type has a single constructor, e.g. `&T` or a struct. + Single, + /// This type has the following list of constructors. + Variants { variants: Vec, non_exhaustive: bool }, + /// The type is spanned by integer values. The range or ranges give the set of allowed values. + /// The second range is only useful for `char`. + /// This is reused for bool. FIXME: don't. + /// `non_exhaustive` is used when the range is not allowed to be matched exhaustively (that's + /// for usize/isize). + Integers { range_1: IntRange, range_2: Option, non_exhaustive: bool }, + /// The type is matched by slices. The usize is the compile-time length of the array, if known. + Slice(Option), + /// The type is matched by slices whose elements are uninhabited. + SliceOfEmpty, + /// The constructors cannot be listed, and the type cannot be matched exhaustively. E.g. `str`, + /// floats. + Unlistable, + /// The type has no inhabitants. + Uninhabited, } -/// A wildcard constructor that we split relative to the constructors in the matrix, as explained -/// at the top of the file. +/// Describes the result of analyzing the constructors in a column of a match. /// -/// A constructor that is not present in the matrix rows will only be covered by the rows that have -/// wildcards. Thus we can group all of those constructors together; we call them "missing -/// constructors". Splitting a wildcard would therefore list all present constructors individually -/// (or grouped if they are integers or slices), and then all missing constructors together as a -/// group. +/// `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. /// -/// However we can go further: since any constructor will match the wildcard rows, and having more -/// rows can only reduce the amount of usefulness witnesses, we can skip the present constructors -/// and only try the missing ones. -/// This will not preserve the whole list of witnesses, but will preserve whether the list is empty -/// or not. In fact this is quite natural from the point of view of diagnostics too. This is done -/// in `to_ctors`: in some cases we only return `Missing`. -#[derive(Debug)] -pub(super) struct SplitWildcard<'tcx> { - /// Constructors (other than wildcards and opaques) seen in the matrix. - matrix_ctors: Vec>, - /// All the constructors for this type - all_ctors: SmallVec<[Constructor<'tcx>; 1]>, +/// 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`. +struct SplitConstructorSet<'tcx> { + present: SmallVec<[Constructor<'tcx>; 1]>, + missing: Vec>, + /// For the `non_exhaustive_omitted_patterns` lint. + nonexhaustive_enum_missing_real_variants: bool, } -impl<'tcx> SplitWildcard<'tcx> { - pub(super) fn new<'p>(pcx: &PatCtxt<'_, 'p, 'tcx>) -> Self { - debug!("SplitWildcard::new({:?})", pcx.ty); - let cx = pcx.cx; - let make_range = |start, end| { - IntRange( - // `unwrap()` is ok because we know the type is an integer. - IntRange::from_range(cx.tcx, start, end, pcx.ty, RangeEnd::Included), - ) - }; - // This determines the set of all possible constructors for the type `pcx.ty`. For numbers, +impl ConstructorSet { + pub(super) fn for_ty<'p, 'tcx>(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> Self { + debug!("ConstructorSet::for_ty({:?})", ty); + let make_range = + |start, end| IntRange::from_range(cx.tcx, start, end, ty, RangeEnd::Included); + // This determines the set of all possible constructors for the type `ty`. For numbers, // arrays and slices we use ranges and variable-length slices when appropriate. // // If the `exhaustive_patterns` feature is enabled, we make sure to omit constructors that // are statically impossible. E.g., for `Option`, we do not include `Some(_)` in the // returned list of constructors. - // Invariant: this is empty if and only if the type is uninhabited (as determined by + // Invariant: this is `Uninhabited` if and only if the type is uninhabited (as determined by // `cx.is_uninhabited()`). - let all_ctors = match pcx.ty.kind() { - ty::Bool => smallvec![make_range(0, 1)], + match ty.kind() { + ty::Bool => { + Self::Integers { range_1: make_range(0, 1), range_2: None, non_exhaustive: false } + } + ty::Char => { + // The valid Unicode Scalar Value ranges. + Self::Integers { + range_1: make_range('\u{0000}' as u128, '\u{D7FF}' as u128), + range_2: Some(make_range('\u{E000}' as u128, '\u{10FFFF}' as u128)), + non_exhaustive: false, + } + } + &ty::Int(ity) => { + // `usize`/`isize` are not allowed to be matched exhaustively unless the + // `precise_pointer_size_matching` feature is enabled. + let non_exhaustive = + ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching; + let bits = Integer::from_int_ty(&cx.tcx, ity).size().bits() as u128; + let min = 1u128 << (bits - 1); + let max = min - 1; + Self::Integers { range_1: make_range(min, max), non_exhaustive, range_2: None } + } + &ty::Uint(uty) => { + // `usize`/`isize` are not allowed to be matched exhaustively unless the + // `precise_pointer_size_matching` feature is enabled. + let non_exhaustive = + ty.is_ptr_sized_integral() && !cx.tcx.features().precise_pointer_size_matching; + let size = Integer::from_uint_ty(&cx.tcx, uty).size(); + let max = size.truncate(u128::MAX); + Self::Integers { range_1: make_range(0, max), non_exhaustive, range_2: None } + } ty::Array(sub_ty, len) if len.try_eval_target_usize(cx.tcx, cx.param_env).is_some() => { let len = len.eval_target_usize(cx.tcx, cx.param_env) as usize; if len != 0 && cx.is_uninhabited(*sub_ty) { - smallvec![] + Self::Uninhabited } else { - smallvec![Slice(Slice::new(Some(len), VarLen(0, 0)))] + Self::Slice(Some(len)) } } // Treat arrays of a constant but unknown length like slices. ty::Array(sub_ty, _) | ty::Slice(sub_ty) => { - let kind = if cx.is_uninhabited(*sub_ty) { FixedLen(0) } else { VarLen(0, 0) }; - smallvec![Slice(Slice::new(None, kind))] + if cx.is_uninhabited(*sub_ty) { + Self::SliceOfEmpty + } else { + Self::Slice(None) + } } ty::Adt(def, args) if def.is_enum() => { // If the enum is declared as `#[non_exhaustive]`, we treat it as if it had an @@ -863,19 +995,14 @@ impl<'tcx> SplitWildcard<'tcx> { // // we don't want to show every possible IO error, but instead have only `_` as the // witness. - let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(pcx.ty); - - let is_exhaustive_pat_feature = cx.tcx.features().exhaustive_patterns; - - // If `exhaustive_patterns` is disabled and our scrutinee is an empty enum, we treat it - // as though it had an "unknown" constructor to avoid exposing its emptiness. The - // exception is if the pattern is at the top level, because we want empty matches to be - // considered exhaustive. - let is_secretly_empty = - def.variants().is_empty() && !is_exhaustive_pat_feature && !pcx.is_top_level; + let is_declared_nonexhaustive = cx.is_foreign_non_exhaustive_enum(ty); - let mut ctors: SmallVec<[_; 1]> = - def.variants() + if def.variants().is_empty() && !is_declared_nonexhaustive { + Self::Uninhabited + } else { + let is_exhaustive_pat_feature = cx.tcx.features().exhaustive_patterns; + let variants: Vec<_> = def + .variants() .iter_enumerated() .filter(|(_, v)| { // If `exhaustive_patterns` is enabled, we exclude variants known to be @@ -885,135 +1012,150 @@ impl<'tcx> SplitWildcard<'tcx> { .instantiate(cx.tcx, args) .apply(cx.tcx, cx.param_env, cx.module) }) - .map(|(idx, _)| Variant(idx)) + .map(|(idx, _)| idx) .collect(); - if is_secretly_empty || is_declared_nonexhaustive { - ctors.push(NonExhaustive); + Self::Variants { variants, non_exhaustive: is_declared_nonexhaustive } } - ctors - } - ty::Char => { - smallvec![ - // The valid Unicode Scalar Value ranges. - make_range('\u{0000}' as u128, '\u{D7FF}' as u128), - make_range('\u{E000}' as u128, '\u{10FFFF}' as u128), - ] - } - ty::Int(_) | ty::Uint(_) - if pcx.ty.is_ptr_sized_integral() - && !cx.tcx.features().precise_pointer_size_matching => - { - // `usize`/`isize` are not allowed to be matched exhaustively unless the - // `precise_pointer_size_matching` feature is enabled. So we treat those types like - // `#[non_exhaustive]` enums by returning a special unmatchable constructor. - smallvec![NonExhaustive] } - &ty::Int(ity) => { - let bits = Integer::from_int_ty(&cx.tcx, ity).size().bits() as u128; - let min = 1u128 << (bits - 1); - let max = min - 1; - smallvec![make_range(min, max)] - } - &ty::Uint(uty) => { - let size = Integer::from_uint_ty(&cx.tcx, uty).size(); - let max = size.truncate(u128::MAX); - smallvec![make_range(0, max)] - } - // If `exhaustive_patterns` is disabled and our scrutinee is the never type, we cannot - // expose its emptiness. The exception is if the pattern is at the top level, because we - // want empty matches to be considered exhaustive. - ty::Never if !cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => { - smallvec![NonExhaustive] - } - ty::Never => smallvec![], - _ if cx.is_uninhabited(pcx.ty) => smallvec![], - ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => smallvec![Single], + ty::Never => Self::Uninhabited, + _ if cx.is_uninhabited(ty) => Self::Uninhabited, + ty::Adt(..) | ty::Tuple(..) | ty::Ref(..) => Self::Single, // This type is one for which we cannot list constructors, like `str` or `f64`. - _ => smallvec![NonExhaustive], - }; - - SplitWildcard { matrix_ctors: Vec::new(), all_ctors } + _ => Self::Unlistable, + } } - /// Pass a set of constructors relative to which to split this one. Don't call twice, it won't - /// do what you want. - pub(super) fn split<'a>( - &mut self, + /// 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. + fn split<'a, 'tcx>( + &self, pcx: &PatCtxt<'_, '_, 'tcx>, ctors: impl Iterator> + Clone, - ) where + ) -> SplitConstructorSet<'tcx> + where 'tcx: 'a, { - // Since `all_ctors` never contains wildcards, this won't recurse further. - self.all_ctors = - self.all_ctors.iter().flat_map(|ctor| ctor.split(pcx, ctors.clone())).collect(); - self.matrix_ctors = ctors.filter(|c| !matches!(c, Wildcard | Opaque)).cloned().collect(); - } - - /// Whether there are any value constructors for this type that are not present in the matrix. - fn any_missing(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool { - self.iter_missing(pcx).next().is_some() - } + let mut missing = Vec::new(); + let mut present: SmallVec<[_; 1]> = SmallVec::new(); + // Constructors in `ctors`, except wildcards. + let mut seen = Vec::new(); + for ctor in ctors.cloned() { + match ctor { + // Wildcards in `ctors` are irrelevant to splitting + Opaque | Wildcard => {} + _ => { + seen.push(ctor); + } + } + } + let mut nonexhaustive_enum_missing_real_variants = false; + match self { + ConstructorSet::Single => { + if seen.is_empty() { + missing.push(Single); + } else { + present.push(Single); + } + } + ConstructorSet::Variants { variants, non_exhaustive } => { + let seen_set: FxHashSet<_> = seen.iter().map(|c| c.as_variant().unwrap()).collect(); + let mut skipped_a_hidden_variant = false; + for variant in variants { + let ctor = Variant(*variant); + if seen_set.contains(&variant) { + present.push(ctor); + } else if ctor.is_doc_hidden_variant(pcx) || ctor.is_unstable_variant(pcx) { + // We don't want to mention any variants that are `doc(hidden)` or behind an + // unstable feature gate if they aren't present in the match. + skipped_a_hidden_variant = true; + } else { + missing.push(ctor); + } + } - /// Iterate over the constructors for this type that are not present in the matrix. - pub(super) fn iter_missing<'a, 'p>( - &'a self, - pcx: &'a PatCtxt<'a, 'p, 'tcx>, - ) -> impl Iterator> + Captures<'p> { - self.all_ctors.iter().filter(move |ctor| !ctor.is_covered_by_any(pcx, &self.matrix_ctors)) - } + if *non_exhaustive { + nonexhaustive_enum_missing_real_variants = !missing.is_empty(); + missing.push(NonExhaustive); + } else if skipped_a_hidden_variant { + // FIXME(Nadrieril): This represents the skipped variants, but isn't super + // clean. Using `NonExhaustive` breaks things elsewhere. + missing.push(Wildcard); + } + } + ConstructorSet::Integers { range_1, range_2, non_exhaustive } => { + let seen_ranges = seen.iter().map(|ctor| ctor.as_int_range().unwrap()).cloned(); + for (seen, splitted_range) in range_1.split(seen_ranges.clone()) { + match seen { + Presence::Unseen => missing.push(IntRange(splitted_range)), + Presence::Seen => present.push(IntRange(splitted_range)), + } + } + if let Some(range_2) = range_2 { + for (seen, splitted_range) in range_2.split(seen_ranges) { + match seen { + Presence::Unseen => missing.push(IntRange(splitted_range)), + Presence::Seen => present.push(IntRange(splitted_range)), + } + } + } - /// Return the set of constructors resulting from splitting the wildcard. As explained at the - /// top of the file, if any constructors are missing we can ignore the present ones. - fn into_ctors(self, pcx: &PatCtxt<'_, '_, 'tcx>) -> SmallVec<[Constructor<'tcx>; 1]> { - if self.any_missing(pcx) { - // Some constructors are missing, thus we can specialize with the special `Missing` - // constructor, which stands for those constructors that are not seen in the matrix, - // and matches the same rows as any of them (namely the wildcard rows). See the top of - // the file for details. - // However, when all constructors are missing we can also specialize with the full - // `Wildcard` constructor. The difference will depend on what we want 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 - // sometimes prefer reporting the list of constructors instead of just `_`. - let report_when_all_missing = pcx.is_top_level && !IntRange::is_integral(pcx.ty); - let ctor = if !self.matrix_ctors.is_empty() || report_when_all_missing { - if pcx.is_non_exhaustive { - Missing { - nonexhaustive_enum_missing_real_variants: self - .iter_missing(pcx) - .any(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))), + if *non_exhaustive { + missing.push(NonExhaustive); + } + } + &ConstructorSet::Slice(array_len) => { + let seen_slices = seen.iter().map(|c| c.as_slice().unwrap()); + let base_slice = Slice { kind: VarLen(0, 0), array_len }; + for (seen, splitted_slice) in base_slice.split(seen_slices) { + let ctor = Slice(splitted_slice); + match seen { + Presence::Unseen => missing.push(ctor), + Presence::Seen => present.push(ctor), } + } + } + ConstructorSet::SliceOfEmpty => { + // Behaves essentially like `Single`. + let slice = Slice(Slice::new(None, FixedLen(0))); + if seen.is_empty() { + missing.push(slice); } else { - Missing { nonexhaustive_enum_missing_real_variants: false } + present.push(slice); } - } else { - Wildcard - }; - return smallvec![ctor]; + } + 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.iter().cloned()); + missing.push(NonExhaustive); + } + // If `exhaustive_patterns` is disabled and our scrutinee is an empty type, we cannot + // expose its emptiness. The exception is if the pattern is at the top level, because we + // want empty matches to be considered exhaustive. + ConstructorSet::Uninhabited + if !pcx.cx.tcx.features().exhaustive_patterns && !pcx.is_top_level => + { + missing.push(NonExhaustive); + } + ConstructorSet::Uninhabited => {} } - // All the constructors are present in the matrix, so we just go through them all. - self.all_ctors + SplitConstructorSet { present, missing, nonexhaustive_enum_missing_real_variants } + } + + /// 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 } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 21031e8ba9d7e..68ca0e2ac0466 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -307,7 +307,7 @@ use self::ArmType::*; use self::Usefulness::*; -use super::deconstruct_pat::{Constructor, DeconstructedPat, Fields, SplitWildcard}; +use super::deconstruct_pat::{Constructor, ConstructorSet, DeconstructedPat, Fields}; use crate::errors::{NonExhaustiveOmittedPattern, Uncovered}; use rustc_data_structures::captures::Captures; @@ -368,8 +368,6 @@ pub(super) struct PatCtxt<'a, 'p, 'tcx> { /// 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, - /// Whether the current pattern is from a `non_exhaustive` enum. - pub(super) is_non_exhaustive: bool, } impl<'a, 'p, 'tcx> fmt::Debug for PatCtxt<'a, 'p, 'tcx> { @@ -616,62 +614,41 @@ impl<'p, 'tcx> Usefulness<'p, 'tcx> { 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 list those patterns. - if pcx.is_non_exhaustive { - witnesses - .into_iter() - // Here we don't want the user to try to list all variants, we want them to add - // a wildcard, so we only suggest that. - .map(|witness| { - witness.apply_constructor(pcx, &Constructor::NonExhaustive) - }) - .collect() - } else { - let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - - // This lets us know if we skipped any variants because they are marked - // `doc(hidden)` or they are unstable feature gate (only stdlib types). - let mut hide_variant_show_wild = false; - // Construct for each missing constructor a "wild" version of this - // constructor, 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 mut new_patterns: Vec> = split_wildcard - .iter_missing(pcx) - .filter_map(|missing_ctor| { - // Check if this variant is marked `doc(hidden)` - if missing_ctor.is_doc_hidden_variant(pcx) - || missing_ctor.is_unstable_variant(pcx) - { - hide_variant_show_wild = true; - return None; - } - Some(DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone())) - }) - .collect(); - - if hide_variant_show_wild { - new_patterns.push(DeconstructedPat::wildcard(pcx.ty, pcx.span)); - } - - witnesses - .into_iter() - .flat_map(|witness| { - new_patterns.iter().map(move |pat| { - Witness( - witness - .0 - .iter() - .chain(once(pat)) - .map(DeconstructedPat::clone_and_forget_reachability) - .collect(), - ) - }) + // 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| { + DeconstructedPat::wild_from_ctor(pcx, missing_ctor.clone()) + }) + .collect(); + + witnesses + .into_iter() + .flat_map(|witness| { + new_patterns.iter().map(move |pat| { + Witness( + witness + .0 + .iter() + .chain(once(pat)) + .map(DeconstructedPat::clone_and_forget_reachability) + .collect(), + ) }) - .collect() - } + }) + .collect() } else { witnesses .into_iter() @@ -844,9 +821,8 @@ fn is_useful<'p, 'tcx>( ty = row.head().ty(); } } - let is_non_exhaustive = cx.is_foreign_non_exhaustive_enum(ty); debug!("v.head: {:?}, v.span: {:?}", v.head(), v.head().span()); - let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level, is_non_exhaustive }; + let pcx = &PatCtxt { cx, ty, span: v.head().span(), is_top_level }; let v_ctor = v.head().ctor(); debug!(?v_ctor); @@ -861,7 +837,8 @@ fn is_useful<'p, 'tcx>( } // We split the head constructor of `v`. let split_ctors = v_ctor.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - let is_non_exhaustive_and_wild = is_non_exhaustive && v_ctor.is_wildcard(); + let is_non_exhaustive_and_wild = + cx.is_foreign_non_exhaustive_enum(ty) && v_ctor.is_wildcard(); // 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; @@ -898,24 +875,21 @@ fn is_useful<'p, 'tcx>( Constructor::Missing { nonexhaustive_enum_missing_real_variants: true } ) { - let patterns = { - let mut split_wildcard = SplitWildcard::new(pcx); - split_wildcard.split(pcx, matrix.heads().map(DeconstructedPat::ctor)); - // Construct for each missing constructor a "wild" version of this - // constructor, 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(_)`. - split_wildcard - .iter_missing(pcx) - // Filter out the `NonExhaustive` because we want to list only real - // variants. Also remove any unstable feature gated variants. - // Because of how we computed `nonexhaustive_enum_missing_real_variants`, - // this will not return an empty `Vec`. - .filter(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))) - .cloned() - .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) - .collect::>() - }; + let missing = ConstructorSet::for_ty(pcx.cx, pcx.ty) + .compute_missing(pcx, matrix.heads().map(DeconstructedPat::ctor)); + // Construct for each missing constructor a "wild" version of this + // constructor, 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 patterns = missing + .into_iter() + // Filter out the `NonExhaustive` because we want to list only real + // variants. Also remove any unstable feature gated variants. + // Because of how we computed `nonexhaustive_enum_missing_real_variants`, + // this will not return an empty `Vec`. + .filter(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))) + .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) + .collect::>(); // Report that a match of a `non_exhaustive` enum marked with `non_exhaustive_omitted_patterns` // is not exhaustive enough. From 2f4cab4d214dd8a5e0b3e90d6e517aa97bd94fd9 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 3 Oct 2023 17:09:20 +0200 Subject: [PATCH 05/52] Clarify handling of hidden variants --- .../src/thir/pattern/deconstruct_pat.rs | 135 +++++++++--------- .../src/thir/pattern/usefulness.rs | 15 +- 2 files changed, 76 insertions(+), 74 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 ab30f5109c77d..2a3fd416a5281 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -609,19 +609,23 @@ pub(super) enum Constructor<'tcx> { /// boxes for the purposes of exhaustiveness: we must not inspect them, and they /// don't count towards making a match exhaustive. Opaque, + /// Or-pattern. + Or, + /// Wildcard pattern. + Wildcard, /// Fake extra constructor for enums that aren't allowed to be matched exhaustively. Also used /// for those types for which we cannot list constructors explicitly, like `f64` and `str`. NonExhaustive, - /// Stands for constructors that are not seen in the matrix, as explained in the code for - /// [`Constructor::split`]. The carried `bool` is used for the `non_exhaustive_omitted_patterns` - /// lint. + /// Fake extra constructor for variants that should not be mentioned in diagnostics. + /// 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`]. The carried `bool` is used for the + /// `non_exhaustive_omitted_patterns` lint. Missing { - nonexhaustive_enum_missing_real_variants: bool, + nonexhaustive_enum_missing_visible_variants: bool, }, - /// Wildcard pattern. - Wildcard, - /// Or-pattern. - Or, } impl<'tcx> Constructor<'tcx> { @@ -652,32 +656,6 @@ impl<'tcx> Constructor<'tcx> { } } - /// Checks if the `Constructor` is a variant and `TyCtxt::eval_stability` returns - /// `EvalResult::Deny { .. }`. - /// - /// This means that the variant has a stdlib unstable feature marking it. - pub(super) fn is_unstable_variant(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool { - if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() { - let variant_def_id = adt.variant(*idx).def_id; - // Filter variants that depend on a disabled unstable feature. - return matches!( - pcx.cx.tcx.eval_stability(variant_def_id, None, DUMMY_SP, None), - EvalResult::Deny { .. } - ); - } - false - } - - /// Checks if the `Constructor` is a `Constructor::Variant` with a `#[doc(hidden)]` - /// attribute from a type not local to the current crate. - pub(super) fn is_doc_hidden_variant(&self, pcx: &PatCtxt<'_, '_, 'tcx>) -> bool { - if let Constructor::Variant(idx) = self && let ty::Adt(adt, _) = pcx.ty.kind() { - let variant_def_id = adt.variants()[*idx].def_id; - return pcx.cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local(); - } - false - } - fn variant_index_for_adt(&self, adt: ty::AdtDef<'tcx>) -> VariantIdx { match *self { Variant(idx) => idx, @@ -713,8 +691,9 @@ impl<'tcx> Constructor<'tcx> { | F32Range(..) | F64Range(..) | IntRange(..) - | NonExhaustive | Opaque + | NonExhaustive + | Hidden | Missing { .. } | Wildcard => 0, Or => bug!("The `Or` constructor doesn't have a fixed arity"), @@ -795,8 +774,8 @@ impl<'tcx> Constructor<'tcx> { Wildcard } else { Missing { - nonexhaustive_enum_missing_real_variants: split_set - .nonexhaustive_enum_missing_real_variants, + nonexhaustive_enum_missing_visible_variants: split_set + .nonexhaustive_enum_missing_visible_variants, } }; smallvec![ctor] @@ -828,8 +807,8 @@ impl<'tcx> Constructor<'tcx> { match (self, other) { // Wildcards cover anything (_, Wildcard) => true, - // The missing ctors are not covered by anything in the matrix except wildcards. - (Missing { .. } | Wildcard, _) => false, + // Only a wildcard pattern can match these special constructors. + (Wildcard | Missing { .. } | NonExhaustive | Hidden, _) => false, (Single, Single) => true, (Variant(self_id), Variant(other_id)) => self_id == other_id, @@ -860,8 +839,6 @@ impl<'tcx> Constructor<'tcx> { // We are trying to inspect an opaque constant. Thus we skip the row. (Opaque, _) | (_, Opaque) => false, - // Only a wildcard pattern can match the special extra constructor. - (NonExhaustive, _) => false, _ => span_bug!( pcx.span, @@ -878,7 +855,14 @@ pub(super) enum ConstructorSet { /// The type has a single constructor, e.g. `&T` or a struct. Single, /// This type has the following list of constructors. - Variants { variants: Vec, non_exhaustive: bool }, + /// Some variants are hidden, which means they won't be mentioned in diagnostics unless the user + /// mentioned them first. We use this for variants behind an unstable gate as well as + /// `#[doc(hidden)]` ones. + Variants { + visible_variants: Vec, + hidden_variants: Vec, + non_exhaustive: bool, + }, /// The type is spanned by integer values. The range or ranges give the set of allowed values. /// The second range is only useful for `char`. /// This is reused for bool. FIXME: don't. @@ -915,7 +899,7 @@ struct SplitConstructorSet<'tcx> { present: SmallVec<[Constructor<'tcx>; 1]>, missing: Vec>, /// For the `non_exhaustive_omitted_patterns` lint. - nonexhaustive_enum_missing_real_variants: bool, + nonexhaustive_enum_missing_visible_variants: bool, } impl ConstructorSet { @@ -1001,7 +985,7 @@ impl ConstructorSet { Self::Uninhabited } else { let is_exhaustive_pat_feature = cx.tcx.features().exhaustive_patterns; - let variants: Vec<_> = def + let (hidden_variants, visible_variants) = def .variants() .iter_enumerated() .filter(|(_, v)| { @@ -1013,9 +997,24 @@ impl ConstructorSet { .apply(cx.tcx, cx.param_env, cx.module) }) .map(|(idx, _)| idx) - .collect(); - - Self::Variants { variants, non_exhaustive: is_declared_nonexhaustive } + .partition(|idx| { + let variant_def_id = def.variant(*idx).def_id; + // Filter variants that depend on a disabled unstable feature. + let is_unstable = matches!( + cx.tcx.eval_stability(variant_def_id, None, DUMMY_SP, None), + EvalResult::Deny { .. } + ); + // Filter foreign `#[doc(hidden)]` variants. + let is_doc_hidden = + cx.tcx.is_doc_hidden(variant_def_id) && !variant_def_id.is_local(); + is_unstable || is_doc_hidden + }); + + Self::Variants { + visible_variants, + hidden_variants, + non_exhaustive: is_declared_nonexhaustive, + } } } ty::Never => Self::Uninhabited, @@ -1050,7 +1049,7 @@ impl ConstructorSet { } } } - let mut nonexhaustive_enum_missing_real_variants = false; + let mut nonexhaustive_enum_missing_visible_variants = false; match self { ConstructorSet::Single => { if seen.is_empty() { @@ -1059,29 +1058,34 @@ impl ConstructorSet { present.push(Single); } } - ConstructorSet::Variants { variants, non_exhaustive } => { + ConstructorSet::Variants { visible_variants, hidden_variants, non_exhaustive } => { let seen_set: FxHashSet<_> = seen.iter().map(|c| c.as_variant().unwrap()).collect(); let mut skipped_a_hidden_variant = false; - for variant in variants { + for variant in visible_variants { let ctor = Variant(*variant); if seen_set.contains(&variant) { present.push(ctor); - } else if ctor.is_doc_hidden_variant(pcx) || ctor.is_unstable_variant(pcx) { - // We don't want to mention any variants that are `doc(hidden)` or behind an - // unstable feature gate if they aren't present in the match. - skipped_a_hidden_variant = true; } else { missing.push(ctor); } } + nonexhaustive_enum_missing_visible_variants = + *non_exhaustive && !missing.is_empty(); + + for variant in hidden_variants { + let ctor = Variant(*variant); + if seen_set.contains(&variant) { + present.push(ctor); + } else { + skipped_a_hidden_variant = true; + } + } + if skipped_a_hidden_variant { + missing.push(Hidden); + } if *non_exhaustive { - nonexhaustive_enum_missing_real_variants = !missing.is_empty(); missing.push(NonExhaustive); - } else if skipped_a_hidden_variant { - // FIXME(Nadrieril): This represents the skipped variants, but isn't super - // clean. Using `NonExhaustive` breaks things elsewhere. - missing.push(Wildcard); } } ConstructorSet::Integers { range_1, range_2, non_exhaustive } => { @@ -1142,7 +1146,7 @@ impl ConstructorSet { ConstructorSet::Uninhabited => {} } - SplitConstructorSet { present, missing, nonexhaustive_enum_missing_real_variants } + SplitConstructorSet { present, missing, nonexhaustive_enum_missing_visible_variants } } /// Compute the set of constructors missing from this column. @@ -1272,8 +1276,9 @@ impl<'p, 'tcx> Fields<'p, 'tcx> { | F32Range(..) | F64Range(..) | IntRange(..) - | NonExhaustive | Opaque + | NonExhaustive + | Hidden | Missing { .. } | Wildcard => Fields::empty(), Or => { @@ -1587,7 +1592,7 @@ impl<'p, 'tcx> DeconstructedPat<'p, 'tcx> { } &Str(value) => PatKind::Constant { value }, IntRange(range) => return range.to_pat(cx.tcx, self.ty), - Wildcard | NonExhaustive => PatKind::Wild, + Wildcard | NonExhaustive | Hidden => PatKind::Wild, Missing { .. } => bug!( "trying to convert a `Missing` constructor into a `Pat`; this is probably a bug, `Missing` should have been processed in `apply_constructors`" @@ -1770,15 +1775,15 @@ 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}"), IntRange(range) => write!(f, "{range:?}"), // Best-effort, will render e.g. `false` as `0..=0` - Wildcard | Missing { .. } | NonExhaustive => write!(f, "_ : {:?}", self.ty), + Str(value) => write!(f, "{value}"), + Opaque => write!(f, ""), Or => { for pat in self.iter_fields() { write!(f, "{}{:?}", start_or_continue(" | "), pat)?; } Ok(()) } - Str(value) => write!(f, "{value}"), - Opaque => write!(f, ""), + Wildcard | Missing { .. } | NonExhaustive | Hidden => write!(f, "_ : {:?}", self.ty), } } } diff --git a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs index 68ca0e2ac0466..6cd73c7eaa958 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/usefulness.rs @@ -872,22 +872,19 @@ fn is_useful<'p, 'tcx>( && usefulness.is_useful() && matches!(witness_preference, RealArm) && matches!( &ctor, - Constructor::Missing { nonexhaustive_enum_missing_real_variants: true } + Constructor::Missing { nonexhaustive_enum_missing_visible_variants: true } ) { let missing = ConstructorSet::for_ty(pcx.cx, pcx.ty) .compute_missing(pcx, matrix.heads().map(DeconstructedPat::ctor)); - // Construct for each missing constructor a "wild" version of this - // constructor, 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(_)`. + // Construct for each missing constructor a "wild" version of this constructor, 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 patterns = missing .into_iter() - // Filter out the `NonExhaustive` because we want to list only real - // variants. Also remove any unstable feature gated variants. - // Because of how we computed `nonexhaustive_enum_missing_real_variants`, + // Because of how we computed `nonexhaustive_enum_missing_visible_variants`, // this will not return an empty `Vec`. - .filter(|c| !(c.is_non_exhaustive() || c.is_unstable_variant(pcx))) + .filter(|c| !(matches!(c, Constructor::NonExhaustive | Constructor::Hidden))) .map(|missing_ctor| DeconstructedPat::wild_from_ctor(pcx, missing_ctor)) .collect::>(); From fda0301b3395ebc6d33d9da566027010b37e1adc Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Tue, 3 Oct 2023 19:51:18 +0200 Subject: [PATCH 06/52] Don't collect `seen` if not needed --- .../src/thir/pattern/deconstruct_pat.rs | 30 +++++++------------ 1 file changed, 11 insertions(+), 19 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 2a3fd416a5281..a2bbde250c3d1 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -1036,30 +1036,21 @@ impl ConstructorSet { where 'tcx: 'a, { - let mut missing = Vec::new(); let mut present: SmallVec<[_; 1]> = SmallVec::new(); + let mut missing = Vec::new(); // Constructors in `ctors`, except wildcards. - let mut seen = Vec::new(); - for ctor in ctors.cloned() { - match ctor { - // Wildcards in `ctors` are irrelevant to splitting - Opaque | Wildcard => {} - _ => { - seen.push(ctor); - } - } - } + let mut seen = ctors.filter(|c| !(matches!(c, Opaque | Wildcard))); let mut nonexhaustive_enum_missing_visible_variants = false; match self { ConstructorSet::Single => { - if seen.is_empty() { + if seen.next().is_none() { missing.push(Single); } else { present.push(Single); } } ConstructorSet::Variants { visible_variants, hidden_variants, non_exhaustive } => { - let seen_set: FxHashSet<_> = seen.iter().map(|c| c.as_variant().unwrap()).collect(); + let seen_set: FxHashSet<_> = seen.map(|c| c.as_variant().unwrap()).collect(); let mut skipped_a_hidden_variant = false; for variant in visible_variants { let ctor = Variant(*variant); @@ -1089,15 +1080,16 @@ impl ConstructorSet { } } ConstructorSet::Integers { range_1, range_2, non_exhaustive } => { - let seen_ranges = seen.iter().map(|ctor| ctor.as_int_range().unwrap()).cloned(); - for (seen, splitted_range) in range_1.split(seen_ranges.clone()) { + let seen_ranges: Vec<_> = + seen.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)), Presence::Seen => present.push(IntRange(splitted_range)), } } if let Some(range_2) = range_2 { - for (seen, splitted_range) in range_2.split(seen_ranges) { + for (seen, splitted_range) in range_2.split(seen_ranges.into_iter()) { match seen { Presence::Unseen => missing.push(IntRange(splitted_range)), Presence::Seen => present.push(IntRange(splitted_range)), @@ -1110,7 +1102,7 @@ impl ConstructorSet { } } &ConstructorSet::Slice(array_len) => { - let seen_slices = seen.iter().map(|c| c.as_slice().unwrap()); + let seen_slices = seen.map(|c| c.as_slice().unwrap()); let base_slice = Slice { kind: VarLen(0, 0), array_len }; for (seen, splitted_slice) in base_slice.split(seen_slices) { let ctor = Slice(splitted_slice); @@ -1123,7 +1115,7 @@ impl ConstructorSet { ConstructorSet::SliceOfEmpty => { // Behaves essentially like `Single`. let slice = Slice(Slice::new(None, FixedLen(0))); - if seen.is_empty() { + if seen.next().is_none() { missing.push(slice); } else { present.push(slice); @@ -1132,7 +1124,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.iter().cloned()); + present.extend(seen.cloned()); missing.push(NonExhaustive); } // If `exhaustive_patterns` is disabled and our scrutinee is an empty type, we cannot From edf6a2d3371218043e4858b81fe48c99535cabe7 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Wed, 4 Oct 2023 15:59:16 +0200 Subject: [PATCH 07/52] Clarify for review --- .../src/thir/pattern/deconstruct_pat.rs | 58 +++++++++++-------- 1 file changed, 33 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 a2bbde250c3d1..dd00982f7f627 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -201,18 +201,26 @@ impl IntRange { /// intersections between an output range and a column range are inclusions. No output range /// straddles the boundary of one of the inputs. /// + /// Additionally, we track for each output range whether it is covered by one of the column ranges or not. + /// /// The following input: /// ```text - /// |-------------------------| // `self` - /// |------| |----------| |----| - /// |-------| |-------| + /// (--------------------------) // `self` + /// (------) (----------) (-) + /// (------) (--------) /// ``` - /// would be iterated over as follows: + /// is first intersected with `self`: /// ```text - /// ||---|--||-|---|---|---|--| + /// (--------------------------) // `self` + /// (----) (----------) (-) + /// (------) (--------) /// ``` - /// - /// Additionally, we track for each output range whether it is covered by one of the column ranges or not. + /// and then iterated over as follows: + /// ```text + /// (-(--)-(-)-(------)-)--(-)- + /// ``` + /// where each sequence of dashes is an output range, and dashes outside parentheses are marked + /// as `Presence::Missing`. fn split( &self, column_ranges: impl Iterator, @@ -245,33 +253,30 @@ impl IntRange { .map(unpack_intrange) .flat_map(|[lo, hi]| [(lo, 1), (hi, -1)]) .collect(); + // We sort by boundary, and for each boundary we sort the "closing parentheses" first. The + // order of +1/-1 for a same boundary value is actually irrelevant, because we only look at + // the accumulated count between distinct boundary values. boundaries.sort_unstable(); - // Counter for parenthesis matching. - let mut paren_counter = 0isize; - let boundaries_with_paren_counts = boundaries - .into_iter() - // Accumulate parenthesis counts. - .map(move |(bdy, delta)| { - paren_counter += delta; - (bdy, paren_counter) - }); - let [self_start, self_end] = unpack_intrange(self.clone()); + // Accumulate parenthesis counts. + let mut paren_counter = 0isize; // Gather pairs of adjacent boundaries. let mut prev_bdy = self_start; - let mut prev_paren_count = 0; - boundaries_with_paren_counts - // End with the end of the range. The count is irrelevant. + boundaries + .into_iter() + // End with the end of the range. The count is ignored. .chain(once((self_end, 0))) - // List pairs of adjacent boundaries. - .map(move |(bdy, paren_count)| { - let ret = (prev_bdy, prev_paren_count, bdy); + // List pairs of adjacent boundaries and the count between them. + .map(move |(bdy, delta)| { + // `delta` affects the count as we cross `bdy`, so the relevant count between + // `prev_bdy` and `bdy` is untouched by `delta`. + let ret = (prev_bdy, paren_counter, bdy); prev_bdy = bdy; - prev_paren_count = paren_count; + paren_counter += delta; ret }) - // Skip duplicates. + // Skip empty ranges. .filter(|&(prev_bdy, _, bdy)| prev_bdy != bdy) // Convert back to ranges. .map(move |(prev_bdy, paren_count, bdy)| { @@ -503,7 +508,10 @@ impl Slice { let smaller_lengths; let arity = self.arity(); let mut max_slice = self.kind; + // Tracks the smallest variable-length slice we've seen. Any slice arity above it is + // therefore `Presence::Seen` in the column. let mut min_var_len = usize::MAX; + // Tracks the fixed-length slices we've seen, to mark them as `Presence::Seen`. let mut seen_fixed_lens = FxHashSet::default(); match &mut max_slice { VarLen(max_prefix_len, max_suffix_len) => { From c1b29b338dc37f96f0695e393743ce35508d3704 Mon Sep 17 00:00:00 2001 From: Nadrieril Date: Thu, 5 Oct 2023 00:58:14 +0200 Subject: [PATCH 08/52] Fix handling slices of empty types --- .../src/thir/pattern/deconstruct_pat.rs | 29 ++++++++++---- tests/ui/pattern/usefulness/slice_of_empty.rs | 22 +++++++++++ .../pattern/usefulness/slice_of_empty.stderr | 39 +++++++++++++++++++ 3 files changed, 82 insertions(+), 8 deletions(-) create mode 100644 tests/ui/pattern/usefulness/slice_of_empty.rs create mode 100644 tests/ui/pattern/usefulness/slice_of_empty.stderr 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 dd00982f7f627..a7a000ba31c6f 100644 --- a/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs +++ b/compiler/rustc_mir_build/src/thir/pattern/deconstruct_pat.rs @@ -859,6 +859,7 @@ impl<'tcx> Constructor<'tcx> { } /// Describes the set of all constructors for a type. +#[derive(Debug)] pub(super) enum ConstructorSet { /// The type has a single constructor, e.g. `&T` or a struct. Single, @@ -903,6 +904,7 @@ pub(super) enum ConstructorSet { /// - 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`. +#[derive(Debug)] struct SplitConstructorSet<'tcx> { present: SmallVec<[Constructor<'tcx>; 1]>, missing: Vec>, @@ -911,8 +913,8 @@ struct SplitConstructorSet<'tcx> { } impl ConstructorSet { + #[instrument(level = "debug", skip(cx), ret)] pub(super) fn for_ty<'p, 'tcx>(cx: &MatchCheckCtxt<'p, 'tcx>, ty: Ty<'tcx>) -> Self { - debug!("ConstructorSet::for_ty({:?})", ty); let make_range = |start, end| IntRange::from_range(cx.tcx, start, end, ty, RangeEnd::Included); // This determines the set of all possible constructors for the type `ty`. For numbers, @@ -1036,6 +1038,7 @@ 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. + #[instrument(level = "debug", skip(self, pcx, ctors), ret)] fn split<'a, 'tcx>( &self, pcx: &PatCtxt<'_, '_, 'tcx>, @@ -1111,7 +1114,7 @@ impl ConstructorSet { } &ConstructorSet::Slice(array_len) => { let seen_slices = seen.map(|c| c.as_slice().unwrap()); - let base_slice = Slice { kind: VarLen(0, 0), array_len }; + 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); match seen { @@ -1121,12 +1124,22 @@ impl ConstructorSet { } } ConstructorSet::SliceOfEmpty => { - // Behaves essentially like `Single`. - let slice = Slice(Slice::new(None, FixedLen(0))); - if seen.next().is_none() { - missing.push(slice); - } else { - present.push(slice); + // This one is tricky because even though there's only one possible value of this + // type (namely `[]`), slice patterns of all lengths are allowed, they're just + // 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 base_slice = Slice::new(None, VarLen(0, 0)); + for (seen, splitted_slice) in base_slice.split(seen_slices) { + let ctor = Slice(splitted_slice); + match seen { + Presence::Seen => present.push(ctor), + Presence::Unseen if splitted_slice.arity() == 0 => { + missing.push(Slice(Slice::new(None, FixedLen(0)))) + } + Presence::Unseen => {} + } } } ConstructorSet::Unlistable => { diff --git a/tests/ui/pattern/usefulness/slice_of_empty.rs b/tests/ui/pattern/usefulness/slice_of_empty.rs new file mode 100644 index 0000000000000..fe068871195a2 --- /dev/null +++ b/tests/ui/pattern/usefulness/slice_of_empty.rs @@ -0,0 +1,22 @@ +#![feature(never_type)] +#![feature(exhaustive_patterns)] +#![deny(unreachable_patterns)] + +fn main() {} + +fn foo(nevers: &[!]) { + match nevers { + &[] => (), + }; + + match nevers { + &[] => (), + &[_] => (), //~ ERROR unreachable pattern + &[_, _, ..] => (), //~ ERROR unreachable pattern + }; + + match nevers { + //~^ ERROR non-exhaustive patterns: `&[]` not covered + &[_] => (), //~ ERROR unreachable pattern + }; +} diff --git a/tests/ui/pattern/usefulness/slice_of_empty.stderr b/tests/ui/pattern/usefulness/slice_of_empty.stderr new file mode 100644 index 0000000000000..07bb6b3a67d8e --- /dev/null +++ b/tests/ui/pattern/usefulness/slice_of_empty.stderr @@ -0,0 +1,39 @@ +error: unreachable pattern + --> $DIR/slice_of_empty.rs:14:9 + | +LL | &[_] => (), + | ^^^^ + | +note: the lint level is defined here + --> $DIR/slice_of_empty.rs:3:9 + | +LL | #![deny(unreachable_patterns)] + | ^^^^^^^^^^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice_of_empty.rs:15:9 + | +LL | &[_, _, ..] => (), + | ^^^^^^^^^^^ + +error: unreachable pattern + --> $DIR/slice_of_empty.rs:20:9 + | +LL | &[_] => (), + | ^^^^ + +error[E0004]: non-exhaustive patterns: `&[]` not covered + --> $DIR/slice_of_empty.rs:18:11 + | +LL | match nevers { + | ^^^^^^ pattern `&[]` not covered + | + = note: the matched value is of type `&[!]` +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 | &[_] => (), &[] => todo!(), + | ++++++++++++++++ + +error: aborting due to 4 previous errors + +For more information about this error, try `rustc --explain E0004`. From ae9cec58394d7a38aac17e2873d213d5fcd85f7a Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Fri, 6 Oct 2023 01:17:09 -0700 Subject: [PATCH 09/52] Copy 1-element arrays as scalars, not vectors For `[T; 1]` it's silly to copy as `<1 x T>` when we can just copy as `T`. --- compiler/rustc_codegen_llvm/src/type_of.rs | 7 +++- .../x86_64-array-pair-load-store-merge.rs | 19 +++++++++++ tests/codegen/array-codegen.rs | 22 +++++++++++++ tests/codegen/array-optimized.rs | 33 +++++++++++++++++++ 4 files changed, 80 insertions(+), 1 deletion(-) create mode 100644 tests/assembly/x86_64-array-pair-load-store-merge.rs create mode 100644 tests/codegen/array-optimized.rs diff --git a/compiler/rustc_codegen_llvm/src/type_of.rs b/compiler/rustc_codegen_llvm/src/type_of.rs index dcc62d314fff4..fd4c9572af2fe 100644 --- a/compiler/rustc_codegen_llvm/src/type_of.rs +++ b/compiler/rustc_codegen_llvm/src/type_of.rs @@ -397,7 +397,12 @@ impl<'tcx> LayoutLlvmExt<'tcx> for TyAndLayout<'tcx> { // extracts all the individual values. let ety = element.llvm_type(cx); - return Some(cx.type_vector(ety, *count)); + if *count == 1 { + // Emitting `<1 x T>` would be silly; just use the scalar. + return Some(ety); + } else { + return Some(cx.type_vector(ety, *count)); + } } // FIXME: The above only handled integer arrays; surely more things diff --git a/tests/assembly/x86_64-array-pair-load-store-merge.rs b/tests/assembly/x86_64-array-pair-load-store-merge.rs new file mode 100644 index 0000000000000..4a8e40f85300e --- /dev/null +++ b/tests/assembly/x86_64-array-pair-load-store-merge.rs @@ -0,0 +1,19 @@ +// assembly-output: emit-asm +// compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel +// only-x86_64 +// ignore-sgx + +// Depending on various codegen choices, this might end up copying +// a `<2 x i8>`, an `i16`, or two `i8`s. +// Regardless of those choices, make sure the instructions use (2-byte) words. + +// CHECK-LABEL: array_copy_2_elements: +#[no_mangle] +pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { + // CHECK-NOT: byte + // CHECK-NOT: mov + // CHECK: mov{{.+}}, word ptr + // CHECK-NEXT: mov word ptr + // CHECK-NEXT: ret + *p = *a; +} diff --git a/tests/codegen/array-codegen.rs b/tests/codegen/array-codegen.rs index ba0d444f97e39..bf5ae74679bb2 100644 --- a/tests/codegen/array-codegen.rs +++ b/tests/codegen/array-codegen.rs @@ -32,3 +32,25 @@ pub fn array_copy(a: &[u8; 4], p: &mut [u8; 4]) { // CHECK: store <4 x i8> %[[TEMP2]], ptr %p, align 1 *p = *a; } + +// CHECK-LABEL: @array_copy_1_element +#[no_mangle] +pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) { + // CHECK: %[[LOCAL:.+]] = alloca [1 x i8], align 1 + // CHECK: %[[TEMP1:.+]] = load i8, ptr %a, align 1 + // CHECK: store i8 %[[TEMP1]], ptr %[[LOCAL]], align 1 + // CHECK: %[[TEMP2:.+]] = load i8, ptr %[[LOCAL]], align 1 + // CHECK: store i8 %[[TEMP2]], ptr %p, align 1 + *p = *a; +} + +// CHECK-LABEL: @array_copy_2_elements +#[no_mangle] +pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { + // CHECK: %[[LOCAL:.+]] = alloca [2 x i8], align 1 + // CHECK: %[[TEMP1:.+]] = load <2 x i8>, ptr %a, align 1 + // CHECK: store <2 x i8> %[[TEMP1]], ptr %[[LOCAL]], align 1 + // CHECK: %[[TEMP2:.+]] = load <2 x i8>, ptr %[[LOCAL]], align 1 + // CHECK: store <2 x i8> %[[TEMP2]], ptr %p, align 1 + *p = *a; +} diff --git a/tests/codegen/array-optimized.rs b/tests/codegen/array-optimized.rs new file mode 100644 index 0000000000000..27448fdcfade2 --- /dev/null +++ b/tests/codegen/array-optimized.rs @@ -0,0 +1,33 @@ +// compile-flags: -O + +#![crate_type = "lib"] + +// CHECK-LABEL: @array_copy_1_element +#[no_mangle] +pub fn array_copy_1_element(a: &[u8; 1], p: &mut [u8; 1]) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = load i8, ptr %a, align 1 + // CHECK: store i8 %[[TEMP]], ptr %p, align 1 + // CHECK: ret + *p = *a; +} + +// CHECK-LABEL: @array_copy_2_elements +#[no_mangle] +pub fn array_copy_2_elements(a: &[u8; 2], p: &mut [u8; 2]) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = load <2 x i8>, ptr %a, align 1 + // CHECK: store <2 x i8> %[[TEMP]], ptr %p, align 1 + // CHECK: ret + *p = *a; +} + +// CHECK-LABEL: @array_copy_4_elements +#[no_mangle] +pub fn array_copy_4_elements(a: &[u8; 4], p: &mut [u8; 4]) { + // CHECK-NOT: alloca + // CHECK: %[[TEMP:.+]] = load <4 x i8>, ptr %a, align 1 + // CHECK: store <4 x i8> %[[TEMP]], ptr %p, align 1 + // CHECK: ret + *p = *a; +} From 6b9ee90c2c49e1abf89a294ee2942efbc80aae7b Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 16 Sep 2023 14:36:23 +0000 Subject: [PATCH 10/52] Reuse determine_cgu_reuse from cg_ssa in cg_clif --- .../rustc_codegen_cranelift/src/driver/aot.rs | 30 +------------------ compiler/rustc_codegen_ssa/src/base.rs | 2 +- 2 files changed, 2 insertions(+), 30 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index cc2f5d7271460..7a94c3aaef6a6 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -8,6 +8,7 @@ use std::thread::JoinHandle; use cranelift_object::{ObjectBuilder, ObjectModule}; use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; +use rustc_codegen_ssa::base::determine_cgu_reuse; use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; use rustc_data_structures::profiling::SelfProfilerRef; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; @@ -489,32 +490,3 @@ pub(crate) fn run_aot( concurrency_limiter, }) } - -// Adapted from https://github.com/rust-lang/rust/blob/303d8aff6092709edd4dbd35b1c88e9aa40bf6d8/src/librustc_codegen_ssa/base.rs#L922-L953 -fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse { - if !tcx.dep_graph.is_fully_enabled() { - return CguReuse::No; - } - - let work_product_id = &cgu.work_product_id(); - if tcx.dep_graph.previous_work_product(work_product_id).is_none() { - // We don't have anything cached for this CGU. This can happen - // if the CGU did not exist in the previous session. - return CguReuse::No; - } - - // Try to mark the CGU as green. If it we can do so, it means that nothing - // affecting the LLVM module has changed and we can re-use a cached version. - // If we compile with any kind of LTO, this means we can re-use the bitcode - // of the Pre-LTO stage (possibly also the Post-LTO version but we'll only - // know that later). If we are not doing LTO, there is only one optimized - // version of each module, so we re-use that. - let dep_node = cgu.codegen_dep_node(tcx); - assert!( - !tcx.dep_graph.dep_node_exists(&dep_node), - "CompileCodegenUnit dep-node for CGU `{}` already exists before marking.", - cgu.name() - ); - - if tcx.try_mark_green(&dep_node) { CguReuse::PostLto } else { CguReuse::No } -} diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index 1e4ea73a1724f..ede1dc3dfcd14 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -994,7 +994,7 @@ pub fn provide(providers: &mut Providers) { }; } -fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse { +pub fn determine_cgu_reuse<'tcx>(tcx: TyCtxt<'tcx>, cgu: &CodegenUnit<'tcx>) -> CguReuse { if !tcx.dep_graph.is_fully_enabled() { return CguReuse::No; } From 3dfd9dfe7ce9bf4bcbb4d1d880cd2c75a85b310c Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Sat, 16 Sep 2023 14:36:49 +0000 Subject: [PATCH 11/52] Remove an LTO dependent cgu_reuse_tracker.set_actual_reuse call --- compiler/rustc_codegen_llvm/src/back/lto.rs | 2 -- compiler/rustc_codegen_ssa/src/back/write.rs | 4 ---- compiler/rustc_session/src/cgu_reuse_tracker.rs | 8 +------- 3 files changed, 1 insertion(+), 13 deletions(-) diff --git a/compiler/rustc_codegen_llvm/src/back/lto.rs b/compiler/rustc_codegen_llvm/src/back/lto.rs index cb5acf79135cc..8655aeec13dd6 100644 --- a/compiler/rustc_codegen_llvm/src/back/lto.rs +++ b/compiler/rustc_codegen_llvm/src/back/lto.rs @@ -19,7 +19,6 @@ use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::bug; use rustc_middle::dep_graph::WorkProduct; use rustc_middle::middle::exported_symbols::{SymbolExportInfo, SymbolExportLevel}; -use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, CrateType, Lto}; use std::ffi::{CStr, CString}; @@ -584,7 +583,6 @@ fn thin_lto( copy_jobs.push(work_product); info!(" - {}: re-used", module_name); assert!(cgcx.incr_comp_session_dir.is_some()); - cgcx.cgu_reuse_tracker.set_actual_reuse(module_name, CguReuse::PostLto); continue; } } diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index f192747c8abaa..bc4578719e50b 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -26,7 +26,6 @@ use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::middle::exported_symbols::SymbolExportInfo; use rustc_middle::ty::TyCtxt; -use rustc_session::cgu_reuse_tracker::CguReuseTracker; use rustc_session::config::{self, CrateType, Lto, OutFileName, OutputFilenames, OutputType}; use rustc_session::config::{Passes, SwitchWithOptPath}; use rustc_session::Session; @@ -366,8 +365,6 @@ pub struct CodegenContext { /// The incremental compilation session directory, or None if we are not /// compiling incrementally pub incr_comp_session_dir: Option, - /// Used to update CGU re-use information during the thinlto phase. - pub cgu_reuse_tracker: CguReuseTracker, /// Channel back to the main control thread to send messages to pub coordinator_send: Sender>, } @@ -1119,7 +1116,6 @@ fn start_executing_work( remark: sess.opts.cg.remark.clone(), remark_dir, incr_comp_session_dir: sess.incr_comp_session_dir_opt().map(|r| r.clone()), - cgu_reuse_tracker: sess.cgu_reuse_tracker.clone(), coordinator_send, expanded_args: tcx.sess.expanded_args.clone(), diag_emitter: shared_emitter.clone(), diff --git a/compiler/rustc_session/src/cgu_reuse_tracker.rs b/compiler/rustc_session/src/cgu_reuse_tracker.rs index 8703e5754655f..74b68fa7d3522 100644 --- a/compiler/rustc_session/src/cgu_reuse_tracker.rs +++ b/compiler/rustc_session/src/cgu_reuse_tracker.rs @@ -75,13 +75,7 @@ impl CguReuseTracker { debug!("set_actual_reuse({cgu_name:?}, {kind:?})"); let prev_reuse = data.lock().unwrap().actual_reuse.insert(cgu_name.to_string(), kind); - - if let Some(prev_reuse) = prev_reuse { - // The only time it is legal to overwrite reuse state is when - // we discover during ThinLTO that we can actually reuse the - // post-LTO version of a CGU. - assert_eq!(prev_reuse, CguReuse::PreLto); - } + assert!(prev_reuse.is_none()); } } From e9fa2ca6add1db7f77c90bdc06210be694ed2571 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 19 Sep 2023 11:23:35 +0000 Subject: [PATCH 12/52] Remove cgu_reuse_tracker from Session This removes a bit of global mutable state --- Cargo.lock | 1 + .../rustc_codegen_cranelift/src/driver/aot.rs | 68 ++++---- compiler/rustc_codegen_ssa/Cargo.toml | 1 + compiler/rustc_codegen_ssa/messages.ftl | 24 +++ .../src/assert_module_sources.rs | 149 +++++++++++++++++- compiler/rustc_codegen_ssa/src/back/write.rs | 2 - compiler/rustc_codegen_ssa/src/base.rs | 10 +- compiler/rustc_codegen_ssa/src/errors.rs | 69 ++++++++ compiler/rustc_codegen_ssa/src/lib.rs | 1 + compiler/rustc_incremental/messages.ftl | 14 -- compiler/rustc_incremental/src/errors.rs | 50 ------ compiler/rustc_incremental/src/lib.rs | 1 - compiler/rustc_interface/src/passes.rs | 3 +- compiler/rustc_session/messages.ftl | 9 -- .../rustc_session/src/cgu_reuse_tracker.rs | 130 --------------- compiler/rustc_session/src/errors.rs | 19 --- compiler/rustc_session/src/lib.rs | 1 - compiler/rustc_session/src/session.rs | 11 -- 18 files changed, 284 insertions(+), 279 deletions(-) rename compiler/{rustc_incremental => rustc_codegen_ssa}/src/assert_module_sources.rs (55%) delete mode 100644 compiler/rustc_session/src/cgu_reuse_tracker.rs diff --git a/Cargo.lock b/Cargo.lock index 082bb4be93c0a..1861f986d2053 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -3650,6 +3650,7 @@ dependencies = [ "serde_json", "smallvec", "tempfile", + "thin-vec", "thorin-dwp", "tracing", "windows", diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index 7a94c3aaef6a6..aaead1ffc5fd6 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -7,6 +7,7 @@ use std::sync::Arc; use std::thread::JoinHandle; use cranelift_object::{ObjectBuilder, ObjectModule}; +use rustc_codegen_ssa::assert_module_sources::CguReuse; use rustc_codegen_ssa::back::metadata::create_compressed_metadata_file; use rustc_codegen_ssa::base::determine_cgu_reuse; use rustc_codegen_ssa::{CodegenResults, CompiledModule, CrateInfo, ModuleKind}; @@ -15,7 +16,6 @@ use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; use rustc_metadata::EncodedMetadata; use rustc_middle::dep_graph::{WorkProduct, WorkProductId}; use rustc_middle::mir::mono::{CodegenUnit, MonoItem}; -use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{DebugInfo, OutputFilenames, OutputType}; use rustc_session::Session; @@ -375,43 +375,47 @@ pub(crate) fn run_aot( } } + // Calculate the CGU reuse + let cgu_reuse = tcx.sess.time("find_cgu_reuse", || { + cgus.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::>() + }); + + rustc_codegen_ssa::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| { + for (i, cgu) in cgus.iter().enumerate() { + let cgu_reuse = cgu_reuse[i]; + cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); + } + }); + let global_asm_config = Arc::new(crate::global_asm::GlobalAsmConfig::new(tcx)); let mut concurrency_limiter = ConcurrencyLimiter::new(tcx.sess, cgus.len()); let modules = tcx.sess.time("codegen mono items", || { cgus.iter() - .map(|cgu| { - let cgu_reuse = if backend_config.disable_incr_cache { - CguReuse::No - } else { - determine_cgu_reuse(tcx, cgu) - }; - tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); - - match cgu_reuse { - CguReuse::No => { - let dep_node = cgu.codegen_dep_node(tcx); - tcx.dep_graph - .with_task( - dep_node, - tcx, - ( - backend_config.clone(), - global_asm_config.clone(), - cgu.name(), - concurrency_limiter.acquire(tcx.sess.diagnostic()), - ), - module_codegen, - Some(rustc_middle::dep_graph::hash_result), - ) - .0 - } - CguReuse::PreLto => unreachable!(), - CguReuse::PostLto => { - concurrency_limiter.job_already_done(); - OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) - } + .enumerate() + .map(|(i, cgu)| match cgu_reuse[i] { + CguReuse::No => { + let dep_node = cgu.codegen_dep_node(tcx); + tcx.dep_graph + .with_task( + dep_node, + tcx, + ( + backend_config.clone(), + global_asm_config.clone(), + cgu.name(), + concurrency_limiter.acquire(tcx.sess.diagnostic()), + ), + module_codegen, + Some(rustc_middle::dep_graph::hash_result), + ) + .0 + } + CguReuse::PreLto => unreachable!(), + CguReuse::PostLto => { + concurrency_limiter.job_already_done(); + OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) } }) .collect::>() diff --git a/compiler/rustc_codegen_ssa/Cargo.toml b/compiler/rustc_codegen_ssa/Cargo.toml index 34d0e2d1df663..454e2f806763e 100644 --- a/compiler/rustc_codegen_ssa/Cargo.toml +++ b/compiler/rustc_codegen_ssa/Cargo.toml @@ -16,6 +16,7 @@ pathdiff = "0.2.0" serde_json = "1.0.59" smallvec = { version = "1.8.1", features = ["union", "may_dangle"] } regex = "1.4" +thin-vec = "0.2.12" rustc_serialize = { path = "../rustc_serialize" } rustc_arena = { path = "../rustc_arena" } diff --git a/compiler/rustc_codegen_ssa/messages.ftl b/compiler/rustc_codegen_ssa/messages.ftl index 6648266733614..5881c6236ece6 100644 --- a/compiler/rustc_codegen_ssa/messages.ftl +++ b/compiler/rustc_codegen_ssa/messages.ftl @@ -11,6 +11,9 @@ codegen_ssa_atomic_compare_exchange = Atomic compare-exchange intrinsic missing codegen_ssa_binary_output_to_tty = option `-o` or `--emit` is used to write binary output type `{$shorthand}` to stdout, but stdout is a tty +codegen_ssa_cgu_not_recorded = + CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded + codegen_ssa_check_installed_visual_studio = please ensure that Visual Studio 2017 or later, or Build Tools for Visual Studio were installed with the Visual C++ option. codegen_ssa_copy_path = could not copy {$from} to {$to}: {$error} @@ -39,6 +42,8 @@ codegen_ssa_failed_to_get_layout = failed to get layout for {$ty}: {$err} codegen_ssa_failed_to_write = failed to write {$path}: {$error} +codegen_ssa_field_associated_value_expected = associated value expected for `{$name}` + codegen_ssa_ignoring_emit_path = ignoring emit path because multiple .{$extension} files were produced codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files were produced @@ -46,6 +51,12 @@ codegen_ssa_ignoring_output = ignoring -o because multiple .{$extension} files w codegen_ssa_illegal_link_ordinal_format = illegal ordinal format in `link_ordinal` .note = an unsuffixed integer value, e.g., `1`, is expected +codegen_ssa_incorrect_cgu_reuse_type = + CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least -> + [one] {"at least "} + *[other] {""} + }`{$expected_reuse}` + codegen_ssa_insufficient_vs_code_product = VS Code is a different product, and is not sufficient. codegen_ssa_invalid_link_ordinal_nargs = incorrect number of arguments to `#[link_ordinal]` @@ -153,12 +164,18 @@ codegen_ssa_linker_unsupported_modifier = `as-needed` modifier not supported for codegen_ssa_linking_failed = linking with `{$linker_path}` failed: {$exit_status} +codegen_ssa_malformed_cgu_name = + found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case). + codegen_ssa_metadata_object_file_write = error writing metadata object file: {$error} codegen_ssa_missing_cpp_build_tool_component = or a necessary component may be missing from the "C++ build tools" workload codegen_ssa_missing_memory_ordering = Atomic intrinsic missing memory ordering +codegen_ssa_missing_query_depgraph = + found CGU-reuse attribute but `-Zquery-dep-graph` was not specified + codegen_ssa_msvc_missing_linker = the msvc targets depend on the msvc linker but `link.exe` was not found codegen_ssa_multiple_external_func_decl = multiple declarations of external function `{$function}` from library `{$library_name}` have different calling conventions @@ -166,6 +183,11 @@ codegen_ssa_multiple_external_func_decl = multiple declarations of external func codegen_ssa_multiple_main_functions = entry symbol `main` declared multiple times .help = did you use `#[no_mangle]` on `fn main`? Use `#[start]` instead +codegen_ssa_no_field = no field `{$name}` + +codegen_ssa_no_module_named = + no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names} + codegen_ssa_no_natvis_directory = error enumerating natvis directory: {$error} codegen_ssa_processing_dymutil_failed = processing debug info with `dsymutil` failed: {$status} @@ -297,6 +319,8 @@ codegen_ssa_unknown_atomic_operation = unknown atomic operation codegen_ssa_unknown_atomic_ordering = unknown ordering in atomic intrinsic +codegen_ssa_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified + codegen_ssa_unsupported_arch = unsupported arch `{$arch}` for os `{$os}` codegen_ssa_unsupported_link_self_contained = option `-C link-self-contained` is not supported on this target diff --git a/compiler/rustc_incremental/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs similarity index 55% rename from compiler/rustc_incremental/src/assert_module_sources.rs rename to compiler/rustc_codegen_ssa/src/assert_module_sources.rs index 8e22ab4083eef..a5a16a929ae1f 100644 --- a/compiler/rustc_incremental/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -25,16 +25,22 @@ use crate::errors; use rustc_ast as ast; +use rustc_data_structures::fx::FxHashMap; use rustc_data_structures::unord::UnordSet; +use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; use rustc_hir::def_id::LOCAL_CRATE; use rustc_middle::mir::mono::CodegenUnitNameBuilder; use rustc_middle::ty::TyCtxt; -use rustc_session::cgu_reuse_tracker::*; -use rustc_span::symbol::{sym, Symbol}; +use rustc_session::Session; +use rustc_span::symbol::sym; +use rustc_span::{Span, Symbol}; +use std::borrow::Cow; +use std::fmt::{self}; +use std::sync::{Arc, Mutex}; use thin_vec::ThinVec; #[allow(missing_docs)] -pub fn assert_module_sources(tcx: TyCtxt<'_>) { +pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&CguReuseTracker)) { tcx.dep_graph.with_ignore(|| { if tcx.sess.opts.incremental.is_none() { return; @@ -43,17 +49,30 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>) { let available_cgus = tcx.collect_and_partition_mono_items(()).1.iter().map(|cgu| cgu.name()).collect(); - let ams = AssertModuleSource { tcx, available_cgus }; + let ams = AssertModuleSource { + tcx, + available_cgus, + cgu_reuse_tracker: if tcx.sess.opts.unstable_opts.query_dep_graph { + CguReuseTracker::new() + } else { + CguReuseTracker::new_disabled() + }, + }; for attr in tcx.hir().attrs(rustc_hir::CRATE_HIR_ID) { ams.check_attr(attr); } - }) + + set_reuse(&ams.cgu_reuse_tracker); + + ams.cgu_reuse_tracker.check_expected_reuse(tcx.sess); + }); } struct AssertModuleSource<'tcx> { tcx: TyCtxt<'tcx>, available_cgus: UnordSet, + cgu_reuse_tracker: CguReuseTracker, } impl<'tcx> AssertModuleSource<'tcx> { @@ -129,7 +148,7 @@ impl<'tcx> AssertModuleSource<'tcx> { }); } - self.tcx.sess.cgu_reuse_tracker.set_expectation( + self.cgu_reuse_tracker.set_expectation( cgu_name, &user_path, attr.span, @@ -169,3 +188,121 @@ impl<'tcx> AssertModuleSource<'tcx> { false } } + +#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] +pub enum CguReuse { + No, + PreLto, + PostLto, +} + +impl fmt::Display for CguReuse { + fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { + match *self { + CguReuse::No => write!(f, "No"), + CguReuse::PreLto => write!(f, "PreLto "), + CguReuse::PostLto => write!(f, "PostLto "), + } + } +} + +impl IntoDiagnosticArg for CguReuse { + fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { + DiagnosticArgValue::Str(Cow::Owned(self.to_string())) + } +} + +#[derive(Copy, Clone, Debug, PartialEq)] +pub enum ComparisonKind { + Exact, + AtLeast, +} + +struct TrackerData { + actual_reuse: FxHashMap, + expected_reuse: FxHashMap, +} + +// Span does not implement `Send`, so we can't just store it in the shared +// `TrackerData` object. Instead of splitting up `TrackerData` into shared and +// non-shared parts (which would be complicated), we just mark the `Span` here +// explicitly as `Send`. That's safe because the span data here is only ever +// accessed from the main thread. +struct SendSpan(Span); +unsafe impl Send for SendSpan {} + +#[derive(Clone)] +pub struct CguReuseTracker { + data: Option>>, +} + +impl CguReuseTracker { + pub fn new() -> CguReuseTracker { + let data = + TrackerData { actual_reuse: Default::default(), expected_reuse: Default::default() }; + + CguReuseTracker { data: Some(Arc::new(Mutex::new(data))) } + } + + pub fn new_disabled() -> CguReuseTracker { + CguReuseTracker { data: None } + } + + pub fn set_actual_reuse(&self, cgu_name: &str, kind: CguReuse) { + if let Some(ref data) = self.data { + debug!("set_actual_reuse({cgu_name:?}, {kind:?})"); + + let prev_reuse = data.lock().unwrap().actual_reuse.insert(cgu_name.to_string(), kind); + assert!(prev_reuse.is_none()); + } + } + + pub fn set_expectation( + &self, + cgu_name: Symbol, + cgu_user_name: &str, + error_span: Span, + expected_reuse: CguReuse, + comparison_kind: ComparisonKind, + ) { + if let Some(ref data) = self.data { + debug!("set_expectation({cgu_name:?}, {expected_reuse:?}, {comparison_kind:?})"); + let mut data = data.lock().unwrap(); + + data.expected_reuse.insert( + cgu_name.to_string(), + (cgu_user_name.to_string(), SendSpan(error_span), expected_reuse, comparison_kind), + ); + } + } + + pub fn check_expected_reuse(&self, sess: &Session) { + if let Some(ref data) = self.data { + let data = data.lock().unwrap(); + + for (cgu_name, &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind)) in + &data.expected_reuse + { + if let Some(&actual_reuse) = data.actual_reuse.get(cgu_name) { + let (error, at_least) = match comparison_kind { + ComparisonKind::Exact => (expected_reuse != actual_reuse, false), + ComparisonKind::AtLeast => (actual_reuse < expected_reuse, true), + }; + + if error { + let at_least = if at_least { 1 } else { 0 }; + errors::IncorrectCguReuseType { + span: error_span.0, + cgu_user_name, + actual_reuse, + expected_reuse, + at_least, + }; + } + } else { + sess.emit_fatal(errors::CguNotRecorded { cgu_user_name, cgu_name }); + } + } + } + } +} diff --git a/compiler/rustc_codegen_ssa/src/back/write.rs b/compiler/rustc_codegen_ssa/src/back/write.rs index bc4578719e50b..3d6a212433463 100644 --- a/compiler/rustc_codegen_ssa/src/back/write.rs +++ b/compiler/rustc_codegen_ssa/src/back/write.rs @@ -1965,8 +1965,6 @@ impl OngoingCodegen { } }); - sess.cgu_reuse_tracker.check_expected_reuse(sess); - sess.abort_if_errors(); let work_products = diff --git a/compiler/rustc_codegen_ssa/src/base.rs b/compiler/rustc_codegen_ssa/src/base.rs index ede1dc3dfcd14..198e5696357af 100644 --- a/compiler/rustc_codegen_ssa/src/base.rs +++ b/compiler/rustc_codegen_ssa/src/base.rs @@ -1,3 +1,4 @@ +use crate::assert_module_sources::CguReuse; use crate::back::link::are_upstream_rust_objects_already_included; use crate::back::metadata::create_compressed_metadata_file; use crate::back::write::{ @@ -31,7 +32,6 @@ use rustc_middle::mir::mono::{CodegenUnit, CodegenUnitNameBuilder, MonoItem}; use rustc_middle::query::Providers; use rustc_middle::ty::layout::{HasTyCtxt, LayoutOf, TyAndLayout}; use rustc_middle::ty::{self, Instance, Ty, TyCtxt}; -use rustc_session::cgu_reuse_tracker::CguReuse; use rustc_session::config::{self, CrateType, EntryFnType, OutputType}; use rustc_session::Session; use rustc_span::symbol::sym; @@ -683,6 +683,13 @@ pub fn codegen_crate( codegen_units.iter().map(|cgu| determine_cgu_reuse(tcx, &cgu)).collect::>() }); + crate::assert_module_sources::assert_module_sources(tcx, &|cgu_reuse_tracker| { + for (i, cgu) in codegen_units.iter().enumerate() { + let cgu_reuse = cgu_reuse[i]; + cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); + } + }); + let mut total_codegen_time = Duration::new(0, 0); let start_rss = tcx.sess.opts.unstable_opts.time_passes.then(|| get_resident_set_size()); @@ -727,7 +734,6 @@ pub fn codegen_crate( ongoing_codegen.check_for_errors(tcx.sess); let cgu_reuse = cgu_reuse[i]; - tcx.sess.cgu_reuse_tracker.set_actual_reuse(cgu.name().as_str(), cgu_reuse); match cgu_reuse { CguReuse::No => { diff --git a/compiler/rustc_codegen_ssa/src/errors.rs b/compiler/rustc_codegen_ssa/src/errors.rs index 39b2fa37fbf87..ed6ac9f9c5da8 100644 --- a/compiler/rustc_codegen_ssa/src/errors.rs +++ b/compiler/rustc_codegen_ssa/src/errors.rs @@ -1,5 +1,6 @@ //! Errors emitted by codegen_ssa +use crate::assert_module_sources::CguReuse; use crate::back::command::Command; use crate::fluent_generated as fluent; use rustc_errors::{ @@ -16,6 +17,74 @@ use std::io::Error; use std::path::{Path, PathBuf}; use std::process::ExitStatus; +#[derive(Diagnostic)] +#[diag(codegen_ssa_incorrect_cgu_reuse_type)] +pub struct IncorrectCguReuseType<'a> { + #[primary_span] + pub span: Span, + pub cgu_user_name: &'a str, + pub actual_reuse: CguReuse, + pub expected_reuse: CguReuse, + pub at_least: u8, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_cgu_not_recorded)] +pub struct CguNotRecorded<'a> { + pub cgu_user_name: &'a str, + pub cgu_name: &'a str, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_unknown_reuse_kind)] +pub struct UnknownReuseKind { + #[primary_span] + pub span: Span, + pub kind: Symbol, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_missing_query_depgraph)] +pub struct MissingQueryDepGraph { + #[primary_span] + pub span: Span, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_malformed_cgu_name)] +pub struct MalformedCguName { + #[primary_span] + pub span: Span, + pub user_path: String, + pub crate_name: String, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_no_module_named)] +pub struct NoModuleNamed<'a> { + #[primary_span] + pub span: Span, + pub user_path: &'a str, + pub cgu_name: Symbol, + pub cgu_names: String, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_field_associated_value_expected)] +pub struct FieldAssociatedValueExpected { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + +#[derive(Diagnostic)] +#[diag(codegen_ssa_no_field)] +pub struct NoField { + #[primary_span] + pub span: Span, + pub name: Symbol, +} + #[derive(Diagnostic)] #[diag(codegen_ssa_lib_def_write_failure)] pub struct LibDefWriteFailure { diff --git a/compiler/rustc_codegen_ssa/src/lib.rs b/compiler/rustc_codegen_ssa/src/lib.rs index f6186a290f81f..008da2a7ce076 100644 --- a/compiler/rustc_codegen_ssa/src/lib.rs +++ b/compiler/rustc_codegen_ssa/src/lib.rs @@ -43,6 +43,7 @@ use std::collections::BTreeSet; use std::io; use std::path::{Path, PathBuf}; +pub mod assert_module_sources; pub mod back; pub mod base; pub mod codegen_attrs; diff --git a/compiler/rustc_incremental/messages.ftl b/compiler/rustc_incremental/messages.ftl index 9fa4e0fb27cf1..5d885e07192dd 100644 --- a/compiler/rustc_incremental/messages.ftl +++ b/compiler/rustc_incremental/messages.ftl @@ -46,8 +46,6 @@ incremental_delete_partial = failed to delete partly initialized session dir `{$ incremental_delete_workproduct = file-system error deleting outdated file `{$path}`: {$err} -incremental_field_associated_value_expected = associated value expected for `{$name}` - incremental_finalize = error finalizing incremental compilation session directory `{$path}`: {$err} incremental_finalized_gc_failed = @@ -63,25 +61,15 @@ incremental_load_dep_graph = could not load dep-graph from `{$path}`: {$err} incremental_lock_unsupported = the filesystem for the incremental path at {$session_dir} does not appear to support locking, consider changing the incremental path to a filesystem that supports locking or disable incremental compilation -incremental_malformed_cgu_name = - found malformed codegen unit name `{$user_path}`. codegen units names must always start with the name of the crate (`{$crate_name}` in this case). incremental_missing_depnode = missing `DepNode` variant incremental_missing_if_this_changed = no `#[rustc_if_this_changed]` annotation detected -incremental_missing_query_depgraph = - found CGU-reuse attribute but `-Zquery-dep-graph` was not specified - incremental_move_dep_graph = failed to move dependency graph from `{$from}` to `{$to}`: {$err} incremental_no_cfg = no cfg attribute -incremental_no_field = no field `{$name}` - -incremental_no_module_named = - no module named `{$user_path}` (mangled: {$cgu_name}). available modules: {$cgu_names} - incremental_no_path = no path from `{$source}` to `{$target}` incremental_not_clean = `{$dep_node_str}` should be clean but is not @@ -107,8 +95,6 @@ incremental_undefined_clean_dirty_assertions_item = incremental_unknown_item = unknown item `{$name}` -incremental_unknown_reuse_kind = unknown cgu-reuse-kind `{$kind}` specified - incremental_unrecognized_depnode = unrecognized `DepNode` variant: {$name} incremental_unrecognized_depnode_label = dep-node label `{$label}` not recognized diff --git a/compiler/rustc_incremental/src/errors.rs b/compiler/rustc_incremental/src/errors.rs index deb8767836543..05ed4f7598d4a 100644 --- a/compiler/rustc_incremental/src/errors.rs +++ b/compiler/rustc_incremental/src/errors.rs @@ -40,56 +40,6 @@ pub struct NoPath { pub source: String, } -#[derive(Diagnostic)] -#[diag(incremental_unknown_reuse_kind)] -pub struct UnknownReuseKind { - #[primary_span] - pub span: Span, - pub kind: Symbol, -} - -#[derive(Diagnostic)] -#[diag(incremental_missing_query_depgraph)] -pub struct MissingQueryDepGraph { - #[primary_span] - pub span: Span, -} - -#[derive(Diagnostic)] -#[diag(incremental_malformed_cgu_name)] -pub struct MalformedCguName { - #[primary_span] - pub span: Span, - pub user_path: String, - pub crate_name: String, -} - -#[derive(Diagnostic)] -#[diag(incremental_no_module_named)] -pub struct NoModuleNamed<'a> { - #[primary_span] - pub span: Span, - pub user_path: &'a str, - pub cgu_name: Symbol, - pub cgu_names: String, -} - -#[derive(Diagnostic)] -#[diag(incremental_field_associated_value_expected)] -pub struct FieldAssociatedValueExpected { - #[primary_span] - pub span: Span, - pub name: Symbol, -} - -#[derive(Diagnostic)] -#[diag(incremental_no_field)] -pub struct NoField { - #[primary_span] - pub span: Span, - pub name: Symbol, -} - #[derive(Diagnostic)] #[diag(incremental_assertion_auto)] pub struct AssertionAuto<'a> { diff --git a/compiler/rustc_incremental/src/lib.rs b/compiler/rustc_incremental/src/lib.rs index 220ea194a6de1..e4050099fc12e 100644 --- a/compiler/rustc_incremental/src/lib.rs +++ b/compiler/rustc_incremental/src/lib.rs @@ -13,7 +13,6 @@ extern crate rustc_middle; extern crate tracing; mod assert_dep_graph; -pub mod assert_module_sources; mod errors; mod persist; diff --git a/compiler/rustc_interface/src/passes.rs b/compiler/rustc_interface/src/passes.rs index 0e8f93cef173f..718dbaaafccec 100644 --- a/compiler/rustc_interface/src/passes.rs +++ b/compiler/rustc_interface/src/passes.rs @@ -957,10 +957,9 @@ pub fn start_codegen<'tcx>( codegen_backend.codegen_crate(tcx, metadata, need_metadata_module) }); - // Don't run these test assertions when not doing codegen. Compiletest tries to build + // Don't run this test assertions when not doing codegen. Compiletest tries to build // build-fail tests in check mode first and expects it to not give an error in that case. if tcx.sess.opts.output_types.should_codegen() { - rustc_incremental::assert_module_sources::assert_module_sources(tcx); rustc_symbol_mangling::test::report_symbol_names(tcx); } diff --git a/compiler/rustc_session/messages.ftl b/compiler/rustc_session/messages.ftl index b356b503aa541..fa1b6f9f13d60 100644 --- a/compiler/rustc_session/messages.ftl +++ b/compiler/rustc_session/messages.ftl @@ -5,9 +5,6 @@ session_cannot_enable_crt_static_linux = sanitizer is incompatible with statical session_cannot_mix_and_match_sanitizers = `-Zsanitizer={$first}` is incompatible with `-Zsanitizer={$second}` -session_cgu_not_recorded = - CGU-reuse for `{$cgu_user_name}` is (mangled: `{$cgu_name}`) was not recorded - session_cli_feature_diagnostic_help = add `-Zcrate-attr="feature({$feature})"` to the command-line options to enable @@ -34,12 +31,6 @@ session_hexadecimal_float_literal_not_supported = hexadecimal float literal is n session_incompatible_linker_flavor = linker flavor `{$flavor}` is incompatible with the current target .note = compatible flavors are: {$compatible_list} -session_incorrect_cgu_reuse_type = - CGU-reuse for `{$cgu_user_name}` is `{$actual_reuse}` but should be {$at_least -> - [one] {"at least "} - *[other] {""} - }`{$expected_reuse}` - session_instrumentation_not_supported = {$us} instrumentation is not supported for this target session_int_literal_too_large = integer literal is too large diff --git a/compiler/rustc_session/src/cgu_reuse_tracker.rs b/compiler/rustc_session/src/cgu_reuse_tracker.rs deleted file mode 100644 index 74b68fa7d3522..0000000000000 --- a/compiler/rustc_session/src/cgu_reuse_tracker.rs +++ /dev/null @@ -1,130 +0,0 @@ -//! Some facilities for tracking how codegen-units are reused during incremental -//! compilation. This is used for incremental compilation tests and debug -//! output. - -use crate::errors::{CguNotRecorded, IncorrectCguReuseType}; -use crate::Session; -use rustc_data_structures::fx::FxHashMap; -use rustc_errors::{DiagnosticArgValue, IntoDiagnosticArg}; -use rustc_span::{Span, Symbol}; -use std::borrow::Cow; -use std::fmt::{self}; -use std::sync::{Arc, Mutex}; - -#[derive(Copy, Clone, Debug, PartialEq, PartialOrd)] -pub enum CguReuse { - No, - PreLto, - PostLto, -} - -impl fmt::Display for CguReuse { - fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result { - match *self { - CguReuse::No => write!(f, "No"), - CguReuse::PreLto => write!(f, "PreLto "), - CguReuse::PostLto => write!(f, "PostLto "), - } - } -} - -impl IntoDiagnosticArg for CguReuse { - fn into_diagnostic_arg(self) -> DiagnosticArgValue<'static> { - DiagnosticArgValue::Str(Cow::Owned(self.to_string())) - } -} - -#[derive(Copy, Clone, Debug, PartialEq)] -pub enum ComparisonKind { - Exact, - AtLeast, -} - -struct TrackerData { - actual_reuse: FxHashMap, - expected_reuse: FxHashMap, -} - -// Span does not implement `Send`, so we can't just store it in the shared -// `TrackerData` object. Instead of splitting up `TrackerData` into shared and -// non-shared parts (which would be complicated), we just mark the `Span` here -// explicitly as `Send`. That's safe because the span data here is only ever -// accessed from the main thread. -struct SendSpan(Span); -unsafe impl Send for SendSpan {} - -#[derive(Clone)] -pub struct CguReuseTracker { - data: Option>>, -} - -impl CguReuseTracker { - pub fn new() -> CguReuseTracker { - let data = - TrackerData { actual_reuse: Default::default(), expected_reuse: Default::default() }; - - CguReuseTracker { data: Some(Arc::new(Mutex::new(data))) } - } - - pub fn new_disabled() -> CguReuseTracker { - CguReuseTracker { data: None } - } - - pub fn set_actual_reuse(&self, cgu_name: &str, kind: CguReuse) { - if let Some(ref data) = self.data { - debug!("set_actual_reuse({cgu_name:?}, {kind:?})"); - - let prev_reuse = data.lock().unwrap().actual_reuse.insert(cgu_name.to_string(), kind); - assert!(prev_reuse.is_none()); - } - } - - pub fn set_expectation( - &self, - cgu_name: Symbol, - cgu_user_name: &str, - error_span: Span, - expected_reuse: CguReuse, - comparison_kind: ComparisonKind, - ) { - if let Some(ref data) = self.data { - debug!("set_expectation({cgu_name:?}, {expected_reuse:?}, {comparison_kind:?})"); - let mut data = data.lock().unwrap(); - - data.expected_reuse.insert( - cgu_name.to_string(), - (cgu_user_name.to_string(), SendSpan(error_span), expected_reuse, comparison_kind), - ); - } - } - - pub fn check_expected_reuse(&self, sess: &Session) { - if let Some(ref data) = self.data { - let data = data.lock().unwrap(); - - for (cgu_name, &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind)) in - &data.expected_reuse - { - if let Some(&actual_reuse) = data.actual_reuse.get(cgu_name) { - let (error, at_least) = match comparison_kind { - ComparisonKind::Exact => (expected_reuse != actual_reuse, false), - ComparisonKind::AtLeast => (actual_reuse < expected_reuse, true), - }; - - if error { - let at_least = if at_least { 1 } else { 0 }; - IncorrectCguReuseType { - span: error_span.0, - cgu_user_name, - actual_reuse, - expected_reuse, - at_least, - }; - } - } else { - sess.emit_fatal(CguNotRecorded { cgu_user_name, cgu_name }); - } - } - } - } -} diff --git a/compiler/rustc_session/src/errors.rs b/compiler/rustc_session/src/errors.rs index 5f8bbfca8908d..31094e0d26669 100644 --- a/compiler/rustc_session/src/errors.rs +++ b/compiler/rustc_session/src/errors.rs @@ -1,6 +1,5 @@ use std::num::NonZeroU32; -use crate::cgu_reuse_tracker::CguReuse; use crate::parse::ParseSess; use rustc_ast::token; use rustc_ast::util::literal::LitError; @@ -9,24 +8,6 @@ use rustc_macros::Diagnostic; use rustc_span::{BytePos, Span, Symbol}; use rustc_target::spec::{SplitDebuginfo, StackProtector, TargetTriple}; -#[derive(Diagnostic)] -#[diag(session_incorrect_cgu_reuse_type)] -pub struct IncorrectCguReuseType<'a> { - #[primary_span] - pub span: Span, - pub cgu_user_name: &'a str, - pub actual_reuse: CguReuse, - pub expected_reuse: CguReuse, - pub at_least: u8, -} - -#[derive(Diagnostic)] -#[diag(session_cgu_not_recorded)] -pub struct CguNotRecorded<'a> { - pub cgu_user_name: &'a str, - pub cgu_name: &'a str, -} - pub struct FeatureGateError { pub span: MultiSpan, pub explain: DiagnosticMessage, diff --git a/compiler/rustc_session/src/lib.rs b/compiler/rustc_session/src/lib.rs index d6c746a7bd85d..66a5092ccd495 100644 --- a/compiler/rustc_session/src/lib.rs +++ b/compiler/rustc_session/src/lib.rs @@ -22,7 +22,6 @@ extern crate tracing; use rustc_errors::{DiagnosticMessage, SubdiagnosticMessage}; use rustc_fluent_macro::fluent_messages; -pub mod cgu_reuse_tracker; pub mod utils; pub use lint::{declare_lint, declare_lint_pass, declare_tool_lint, impl_lint_pass}; pub use rustc_lint_defs as lint; diff --git a/compiler/rustc_session/src/session.rs b/compiler/rustc_session/src/session.rs index b484978eed230..5cac11cc8f782 100644 --- a/compiler/rustc_session/src/session.rs +++ b/compiler/rustc_session/src/session.rs @@ -1,4 +1,3 @@ -use crate::cgu_reuse_tracker::CguReuseTracker; use crate::code_stats::CodeStats; pub use crate::code_stats::{DataTypeKind, FieldInfo, FieldKind, SizeKind, VariantInfo}; use crate::config::{ @@ -153,9 +152,6 @@ pub struct Session { pub io: CompilerIO, incr_comp_session: OneThread>, - /// Used for incremental compilation tests. Will only be populated if - /// `-Zquery-dep-graph` is specified. - pub cgu_reuse_tracker: CguReuseTracker, /// Used by `-Z self-profile`. pub prof: SelfProfilerRef, @@ -1431,12 +1427,6 @@ pub fn build_session( }); let print_fuel = AtomicU64::new(0); - let cgu_reuse_tracker = if sopts.unstable_opts.query_dep_graph { - CguReuseTracker::new() - } else { - CguReuseTracker::new_disabled() - }; - let prof = SelfProfilerRef::new( self_profiler, sopts.unstable_opts.time_passes.then(|| sopts.unstable_opts.time_passes_format), @@ -1461,7 +1451,6 @@ pub fn build_session( sysroot, io, incr_comp_session: OneThread::new(RefCell::new(IncrCompSession::NotInitialized)), - cgu_reuse_tracker, prof, perf_stats: PerfStats { symbol_hash_time: Lock::new(Duration::from_secs(0)), From 7f5af72e64ec08addd1398c7b809f149f5ff57c5 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Tue, 19 Sep 2023 11:26:46 +0000 Subject: [PATCH 13/52] Remove interior mutability from CguReuseTracker --- .../src/assert_module_sources.rs | 43 +++++++------------ 1 file changed, 15 insertions(+), 28 deletions(-) diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs index a5a16a929ae1f..27873dd2e1ab7 100644 --- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -35,12 +35,11 @@ use rustc_session::Session; use rustc_span::symbol::sym; use rustc_span::{Span, Symbol}; use std::borrow::Cow; -use std::fmt::{self}; -use std::sync::{Arc, Mutex}; +use std::fmt; use thin_vec::ThinVec; #[allow(missing_docs)] -pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&CguReuseTracker)) { +pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&mut CguReuseTracker)) { tcx.dep_graph.with_ignore(|| { if tcx.sess.opts.incremental.is_none() { return; @@ -49,7 +48,7 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&CguReuseTracke let available_cgus = tcx.collect_and_partition_mono_items(()).1.iter().map(|cgu| cgu.name()).collect(); - let ams = AssertModuleSource { + let mut ams = AssertModuleSource { tcx, available_cgus, cgu_reuse_tracker: if tcx.sess.opts.unstable_opts.query_dep_graph { @@ -63,7 +62,7 @@ pub fn assert_module_sources(tcx: TyCtxt<'_>, set_reuse: &dyn Fn(&CguReuseTracke ams.check_attr(attr); } - set_reuse(&ams.cgu_reuse_tracker); + set_reuse(&mut ams.cgu_reuse_tracker); ams.cgu_reuse_tracker.check_expected_reuse(tcx.sess); }); @@ -76,7 +75,7 @@ struct AssertModuleSource<'tcx> { } impl<'tcx> AssertModuleSource<'tcx> { - fn check_attr(&self, attr: &ast::Attribute) { + fn check_attr(&mut self, attr: &ast::Attribute) { let (expected_reuse, comp_kind) = if attr.has_name(sym::rustc_partition_reused) { (CguReuse::PreLto, ComparisonKind::AtLeast) } else if attr.has_name(sym::rustc_partition_codegened) { @@ -220,20 +219,11 @@ pub enum ComparisonKind { struct TrackerData { actual_reuse: FxHashMap, - expected_reuse: FxHashMap, + expected_reuse: FxHashMap, } -// Span does not implement `Send`, so we can't just store it in the shared -// `TrackerData` object. Instead of splitting up `TrackerData` into shared and -// non-shared parts (which would be complicated), we just mark the `Span` here -// explicitly as `Send`. That's safe because the span data here is only ever -// accessed from the main thread. -struct SendSpan(Span); -unsafe impl Send for SendSpan {} - -#[derive(Clone)] pub struct CguReuseTracker { - data: Option>>, + data: Option, } impl CguReuseTracker { @@ -241,45 +231,42 @@ impl CguReuseTracker { let data = TrackerData { actual_reuse: Default::default(), expected_reuse: Default::default() }; - CguReuseTracker { data: Some(Arc::new(Mutex::new(data))) } + CguReuseTracker { data: Some(data) } } pub fn new_disabled() -> CguReuseTracker { CguReuseTracker { data: None } } - pub fn set_actual_reuse(&self, cgu_name: &str, kind: CguReuse) { - if let Some(ref data) = self.data { + pub fn set_actual_reuse(&mut self, cgu_name: &str, kind: CguReuse) { + if let Some(data) = &mut self.data { debug!("set_actual_reuse({cgu_name:?}, {kind:?})"); - let prev_reuse = data.lock().unwrap().actual_reuse.insert(cgu_name.to_string(), kind); + let prev_reuse = data.actual_reuse.insert(cgu_name.to_string(), kind); assert!(prev_reuse.is_none()); } } pub fn set_expectation( - &self, + &mut self, cgu_name: Symbol, cgu_user_name: &str, error_span: Span, expected_reuse: CguReuse, comparison_kind: ComparisonKind, ) { - if let Some(ref data) = self.data { + if let Some(data) = &mut self.data { debug!("set_expectation({cgu_name:?}, {expected_reuse:?}, {comparison_kind:?})"); - let mut data = data.lock().unwrap(); data.expected_reuse.insert( cgu_name.to_string(), - (cgu_user_name.to_string(), SendSpan(error_span), expected_reuse, comparison_kind), + (cgu_user_name.to_string(), error_span, expected_reuse, comparison_kind), ); } } pub fn check_expected_reuse(&self, sess: &Session) { if let Some(ref data) = self.data { - let data = data.lock().unwrap(); - for (cgu_name, &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind)) in &data.expected_reuse { @@ -292,7 +279,7 @@ impl CguReuseTracker { if error { let at_least = if at_least { 1 } else { 0 }; errors::IncorrectCguReuseType { - span: error_span.0, + span: *error_span, cgu_user_name, actual_reuse, expected_reuse, From f0b5820fa5b29d840e700ee5d760b55d291311c3 Mon Sep 17 00:00:00 2001 From: bjorn3 <17426603+bjorn3@users.noreply.github.com> Date: Thu, 5 Oct 2023 09:49:10 +0000 Subject: [PATCH 14/52] Fix review comments --- compiler/rustc_codegen_cranelift/src/driver/aot.rs | 2 +- compiler/rustc_codegen_ssa/src/assert_module_sources.rs | 8 ++++---- 2 files changed, 5 insertions(+), 5 deletions(-) diff --git a/compiler/rustc_codegen_cranelift/src/driver/aot.rs b/compiler/rustc_codegen_cranelift/src/driver/aot.rs index aaead1ffc5fd6..49f51f9f956bc 100644 --- a/compiler/rustc_codegen_cranelift/src/driver/aot.rs +++ b/compiler/rustc_codegen_cranelift/src/driver/aot.rs @@ -412,7 +412,7 @@ pub(crate) fn run_aot( ) .0 } - CguReuse::PreLto => unreachable!(), + CguReuse::PreLto => unreachable!("LTO not yet supported"), CguReuse::PostLto => { concurrency_limiter.job_already_done(); OngoingModuleCodegen::Sync(reuse_workproduct_for_cgu(tcx, cgu)) diff --git a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs index 27873dd2e1ab7..16bb7b12bd3c1 100644 --- a/compiler/rustc_codegen_ssa/src/assert_module_sources.rs +++ b/compiler/rustc_codegen_ssa/src/assert_module_sources.rs @@ -227,14 +227,14 @@ pub struct CguReuseTracker { } impl CguReuseTracker { - pub fn new() -> CguReuseTracker { + fn new() -> CguReuseTracker { let data = TrackerData { actual_reuse: Default::default(), expected_reuse: Default::default() }; CguReuseTracker { data: Some(data) } } - pub fn new_disabled() -> CguReuseTracker { + fn new_disabled() -> CguReuseTracker { CguReuseTracker { data: None } } @@ -247,7 +247,7 @@ impl CguReuseTracker { } } - pub fn set_expectation( + fn set_expectation( &mut self, cgu_name: Symbol, cgu_user_name: &str, @@ -265,7 +265,7 @@ impl CguReuseTracker { } } - pub fn check_expected_reuse(&self, sess: &Session) { + fn check_expected_reuse(&self, sess: &Session) { if let Some(ref data) = self.data { for (cgu_name, &(ref cgu_user_name, ref error_span, expected_reuse, comparison_kind)) in &data.expected_reuse From b6b11c72c96d69bc622c7a82484c29c3c3365ce7 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 14:02:42 +1100 Subject: [PATCH 15/52] Rejig some top-level `rustc_hir_pretty` functions. There are several that are unused and can be removed. And there are some calls to `to_string`, which can be expressed more nicely as a `foo_to_string` call, and then `to_string` need not be `pub`. (This requires adding `pat_to_string`). --- compiler/rustc_hir_pretty/src/lib.rs | 38 ++----------------- compiler/rustc_hir_typeck/src/pat.rs | 12 ++---- .../src/matches/match_wild_err_arm.rs | 2 +- .../clippy/clippy_lints/src/mut_reference.rs | 2 +- 4 files changed, 8 insertions(+), 46 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 8587b009f25aa..bc5b2a10d9f6e 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -187,7 +187,7 @@ impl<'a> State<'a> { } } -pub fn to_string(ann: &dyn PpAnn, f: F) -> String +fn to_string(ann: &dyn PpAnn, f: F) -> String where F: FnOnce(&mut State<'_>), { @@ -196,48 +196,16 @@ where printer.s.eof() } -pub fn generic_params_to_string(generic_params: &[GenericParam<'_>]) -> String { - to_string(NO_ANN, |s| s.print_generic_params(generic_params)) -} - -pub fn bounds_to_string<'b>(bounds: impl IntoIterator>) -> String { - to_string(NO_ANN, |s| s.print_bounds("", bounds)) -} - pub fn ty_to_string(ty: &hir::Ty<'_>) -> String { to_string(NO_ANN, |s| s.print_type(ty)) } -pub fn path_segment_to_string(segment: &hir::PathSegment<'_>) -> String { - to_string(NO_ANN, |s| s.print_path_segment(segment)) -} - -pub fn path_to_string(segment: &hir::Path<'_>) -> String { - to_string(NO_ANN, |s| s.print_path(segment, false)) -} - pub fn qpath_to_string(segment: &hir::QPath<'_>) -> String { to_string(NO_ANN, |s| s.print_qpath(segment, false)) } -pub fn fn_to_string( - decl: &hir::FnDecl<'_>, - header: hir::FnHeader, - name: Option, - generics: &hir::Generics<'_>, - arg_names: &[Ident], - body_id: Option, -) -> String { - to_string(NO_ANN, |s| s.print_fn(decl, header, name, generics, arg_names, body_id)) -} - -pub fn enum_def_to_string( - enum_definition: &hir::EnumDef<'_>, - generics: &hir::Generics<'_>, - name: Symbol, - span: rustc_span::Span, -) -> String { - to_string(NO_ANN, |s| s.print_enum_def(enum_definition, generics, name, span)) +pub fn pat_to_string(pat: &hir::Pat<'_>) -> String { + to_string(NO_ANN, |s| s.print_pat(pat)) } impl<'a> State<'a> { diff --git a/compiler/rustc_hir_typeck/src/pat.rs b/compiler/rustc_hir_typeck/src/pat.rs index 3f9c9b3381baa..072c7a9f36ad5 100644 --- a/compiler/rustc_hir_typeck/src/pat.rs +++ b/compiler/rustc_hir_typeck/src/pat.rs @@ -1504,9 +1504,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { { let has_shorthand_field_name = field_patterns.iter().any(|field| field.is_shorthand); if has_shorthand_field_name { - let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { - s.print_qpath(qpath, false) - }); + let path = rustc_hir_pretty::qpath_to_string(qpath); let mut err = struct_span_err!( self.tcx.sess, pat.span, @@ -1688,9 +1686,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { return None; } - let path = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { - s.print_qpath(qpath, false) - }); + let path = rustc_hir_pretty::qpath_to_string(qpath); let mut err = struct_span_err!( self.tcx.sess, pat.span, @@ -1740,9 +1736,7 @@ impl<'a, 'tcx> FnCtxt<'a, 'tcx> { f } } - Err(_) => rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| { - s.print_pat(field.pat) - }), + Err(_) => rustc_hir_pretty::pat_to_string(field.pat), } }) .collect::>() diff --git a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs index de911f7a02803..a2903e52ae08d 100644 --- a/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs +++ b/src/tools/clippy/clippy_lints/src/matches/match_wild_err_arm.rs @@ -19,7 +19,7 @@ pub(crate) fn check<'tcx>(cx: &LateContext<'tcx>, ex: &Expr<'tcx>, arms: &[Arm<' if is_type_diagnostic_item(cx, ex_ty, sym::Result) { for arm in arms { if let PatKind::TupleStruct(ref path, inner, _) = arm.pat.kind { - let path_str = rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)); + let path_str = rustc_hir_pretty::qpath_to_string(path); if path_str == "Err" { let mut matching_wild = inner.iter().any(is_wild); let mut ident_bind_name = kw::Underscore; diff --git a/src/tools/clippy/clippy_lints/src/mut_reference.rs b/src/tools/clippy/clippy_lints/src/mut_reference.rs index e53e146ec5dbe..01b850cdb1139 100644 --- a/src/tools/clippy/clippy_lints/src/mut_reference.rs +++ b/src/tools/clippy/clippy_lints/src/mut_reference.rs @@ -49,7 +49,7 @@ impl<'tcx> LateLintPass<'tcx> for UnnecessaryMutPassed { cx, arguments.iter().collect(), cx.typeck_results().expr_ty(fn_expr), - &rustc_hir_pretty::to_string(rustc_hir_pretty::NO_ANN, |s| s.print_qpath(path, false)), + &rustc_hir_pretty::qpath_to_string(path), "function", ); } From 51e8c807277580f3575df4bbd01ebf2bfde941ff Mon Sep 17 00:00:00 2001 From: Trevor Gross Date: Tue, 10 Oct 2023 02:40:26 -0400 Subject: [PATCH 16/52] Add unstable book page for the no-jump-tables codegen option --- .../src/compiler-flags/no-jump-tables.md | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) create mode 100644 src/doc/unstable-book/src/compiler-flags/no-jump-tables.md diff --git a/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md b/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md new file mode 100644 index 0000000000000..f096c20f4bd54 --- /dev/null +++ b/src/doc/unstable-book/src/compiler-flags/no-jump-tables.md @@ -0,0 +1,19 @@ +# `no-jump-tables` + +The tracking issue for this feature is [#116592](https://github.com/rust-lang/rust/issues/116592) + +--- + +This option enables the `-fno-jump-tables` flag for LLVM, which makes the +codegen backend avoid generating jump tables when lowering switches. + +This option adds the LLVM `no-jump-tables=true` attribute to every function. + +The option can be used to help provide protection against +jump-oriented-programming (JOP) attacks, such as with the linux kernel's [IBT]. + +```sh +RUSTFLAGS="-Zno-jump-tables" cargo +nightly build -Z build-std +``` + +[IBT]: https://www.phoronix.com/news/Linux-IBT-By-Default-Tip From 664b1858aac90a75e6bbaca9f3c0726877a04ab3 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 14:01:36 +1100 Subject: [PATCH 17/52] Remove many unneeded `pub`s. --- compiler/rustc_hir_pretty/src/lib.rs | 117 ++++++++++++++------------- 1 file changed, 59 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index bc5b2a10d9f6e..e6388f34eea24 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -75,7 +75,7 @@ pub struct State<'a> { } impl<'a> State<'a> { - pub fn print_node(&mut self, node: Node<'_>) { + fn print_node(&mut self, node: Node<'_>) { match node { Node::Param(a) => self.print_param(a), Node::Item(a) => self.print_item(a), @@ -144,7 +144,7 @@ impl<'a> PrintState<'a> for State<'a> { } } -pub const INDENT_UNIT: isize = 4; +const INDENT_UNIT: isize = 4; /// Requires you to pass an input filename and reader so that /// it can scan the input text for comments to copy forward. @@ -167,7 +167,7 @@ pub fn print_crate<'a>( } impl<'a> State<'a> { - pub fn new_from_input( + fn new_from_input( sm: &'a SourceMap, filename: FileName, input: String, @@ -209,7 +209,7 @@ pub fn pat_to_string(pat: &hir::Pat<'_>) -> String { } impl<'a> State<'a> { - pub fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) { + fn bclose_maybe_open(&mut self, span: rustc_span::Span, close_box: bool) { self.maybe_print_comment(span.hi()); self.break_offset_if_not_bol(1, -INDENT_UNIT); self.word("}"); @@ -218,11 +218,11 @@ impl<'a> State<'a> { } } - pub fn bclose(&mut self, span: rustc_span::Span) { + fn bclose(&mut self, span: rustc_span::Span) { self.bclose_maybe_open(span, true) } - pub fn commasep_cmnt(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G) + fn commasep_cmnt(&mut self, b: Breaks, elts: &[T], mut op: F, mut get_span: G) where F: FnMut(&mut State<'_>, &T), G: FnMut(&T) -> rustc_span::Span, @@ -243,25 +243,25 @@ impl<'a> State<'a> { self.end(); } - pub fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) { + fn commasep_exprs(&mut self, b: Breaks, exprs: &[hir::Expr<'_>]) { self.commasep_cmnt(b, exprs, |s, e| s.print_expr(e), |e| e.span); } - pub fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[ast::Attribute]) { + fn print_mod(&mut self, _mod: &hir::Mod<'_>, attrs: &[ast::Attribute]) { self.print_inner_attributes(attrs); for &item_id in _mod.item_ids { self.ann.nested(self, Nested::Item(item_id)); } } - pub fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) { + fn print_opt_lifetime(&mut self, lifetime: &hir::Lifetime) { if !lifetime.is_elided() { self.print_lifetime(lifetime); self.nbsp(); } } - pub fn print_type(&mut self, ty: &hir::Ty<'_>) { + fn print_type(&mut self, ty: &hir::Ty<'_>) { self.maybe_print_comment(ty.span.lo()); self.ibox(0); match ty.kind { @@ -339,7 +339,7 @@ impl<'a> State<'a> { self.end() } - pub fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) { + fn print_foreign_item(&mut self, item: &hir::ForeignItem<'_>) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); self.print_outer_attributes(self.attrs(item.hir_id())); @@ -447,7 +447,7 @@ impl<'a> State<'a> { } /// Pretty-print an item - pub fn print_item(&mut self, item: &hir::Item<'_>) { + fn print_item(&mut self, item: &hir::Item<'_>) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); let attrs = self.attrs(item.hir_id()); @@ -672,7 +672,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Item(item)) } - pub fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) { + fn print_trait_ref(&mut self, t: &hir::TraitRef<'_>) { self.print_path(t.path, false); } @@ -689,7 +689,7 @@ impl<'a> State<'a> { self.print_trait_ref(&t.trait_ref); } - pub fn print_enum_def( + fn print_enum_def( &mut self, enum_definition: &hir::EnumDef<'_>, generics: &hir::Generics<'_>, @@ -704,7 +704,7 @@ impl<'a> State<'a> { self.print_variants(enum_definition.variants, span); } - pub fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span::Span) { + fn print_variants(&mut self, variants: &[hir::Variant<'_>], span: rustc_span::Span) { self.bopen(); for v in variants { self.space_if_not_bol(); @@ -719,14 +719,14 @@ impl<'a> State<'a> { self.bclose(span) } - pub fn print_defaultness(&mut self, defaultness: hir::Defaultness) { + fn print_defaultness(&mut self, defaultness: hir::Defaultness) { match defaultness { hir::Defaultness::Default { .. } => self.word_nbsp("default"), hir::Defaultness::Final => (), } } - pub fn print_struct( + fn print_struct( &mut self, struct_def: &hir::VariantData<'_>, generics: &hir::Generics<'_>, @@ -775,7 +775,7 @@ impl<'a> State<'a> { } } - pub fn print_variant(&mut self, v: &hir::Variant<'_>) { + fn print_variant(&mut self, v: &hir::Variant<'_>) { self.head(""); let generics = hir::Generics::empty(); self.print_struct(&v.data, generics, v.ident.name, v.span, false); @@ -785,7 +785,8 @@ impl<'a> State<'a> { self.print_anon_const(d); } } - pub fn print_method_sig( + + fn print_method_sig( &mut self, ident: Ident, m: &hir::FnSig<'_>, @@ -796,7 +797,7 @@ impl<'a> State<'a> { self.print_fn(m.decl, m.header, Some(ident.name), generics, arg_names, body_id); } - pub fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) { + fn print_trait_item(&mut self, ti: &hir::TraitItem<'_>) { self.ann.pre(self, AnnNode::SubItem(ti.hir_id())); self.hardbreak_if_not_bol(); self.maybe_print_comment(ti.span.lo()); @@ -824,7 +825,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::SubItem(ti.hir_id())) } - pub fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) { + fn print_impl_item(&mut self, ii: &hir::ImplItem<'_>) { self.ann.pre(self, AnnNode::SubItem(ii.hir_id())); self.hardbreak_if_not_bol(); self.maybe_print_comment(ii.span.lo()); @@ -849,7 +850,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::SubItem(ii.hir_id())) } - pub fn print_local( + fn print_local( &mut self, init: Option<&hir::Expr<'_>>, els: Option<&hir::Block<'_>>, @@ -882,7 +883,7 @@ impl<'a> State<'a> { self.end() } - pub fn print_stmt(&mut self, st: &hir::Stmt<'_>) { + fn print_stmt(&mut self, st: &hir::Stmt<'_>) { self.maybe_print_comment(st.span.lo()); match st.kind { hir::StmtKind::Local(loc) => { @@ -905,19 +906,19 @@ impl<'a> State<'a> { self.maybe_print_trailing_comment(st.span, None) } - pub fn print_block(&mut self, blk: &hir::Block<'_>) { + fn print_block(&mut self, blk: &hir::Block<'_>) { self.print_block_with_attrs(blk, &[]) } - pub fn print_block_unclosed(&mut self, blk: &hir::Block<'_>) { + fn print_block_unclosed(&mut self, blk: &hir::Block<'_>) { self.print_block_maybe_unclosed(blk, &[], false) } - pub fn print_block_with_attrs(&mut self, blk: &hir::Block<'_>, attrs: &[ast::Attribute]) { + fn print_block_with_attrs(&mut self, blk: &hir::Block<'_>, attrs: &[ast::Attribute]) { self.print_block_maybe_unclosed(blk, attrs, true) } - pub fn print_block_maybe_unclosed( + fn print_block_maybe_unclosed( &mut self, blk: &hir::Block<'_>, attrs: &[ast::Attribute], @@ -973,7 +974,7 @@ impl<'a> State<'a> { } } - pub fn print_if( + fn print_if( &mut self, test: &hir::Expr<'_>, blk: &hir::Expr<'_>, @@ -986,14 +987,14 @@ impl<'a> State<'a> { self.print_else(elseopt) } - pub fn print_array_length(&mut self, len: &hir::ArrayLen) { + fn print_array_length(&mut self, len: &hir::ArrayLen) { match len { hir::ArrayLen::Infer(_, _) => self.word("_"), hir::ArrayLen::Body(ct) => self.print_anon_const(ct), } } - pub fn print_anon_const(&mut self, constant: &hir::AnonConst) { + fn print_anon_const(&mut self, constant: &hir::AnonConst) { self.ann.nested(self, Nested::Body(constant.body)) } @@ -1009,7 +1010,7 @@ impl<'a> State<'a> { /// Prints an expr using syntax that's acceptable in a condition position, such as the `cond` in /// `if cond { ... }`. - pub fn print_expr_as_cond(&mut self, expr: &hir::Expr<'_>) { + fn print_expr_as_cond(&mut self, expr: &hir::Expr<'_>) { self.print_expr_cond_paren(expr, Self::cond_needs_par(expr)) } @@ -1328,7 +1329,7 @@ impl<'a> State<'a> { self.pclose(); } - pub fn print_expr(&mut self, expr: &hir::Expr<'_>) { + fn print_expr(&mut self, expr: &hir::Expr<'_>) { self.maybe_print_comment(expr.span.lo()); self.print_outer_attributes(self.attrs(expr.hir_id)); self.ibox(INDENT_UNIT); @@ -1561,7 +1562,7 @@ impl<'a> State<'a> { self.end() } - pub fn print_local_decl(&mut self, loc: &hir::Local<'_>) { + fn print_local_decl(&mut self, loc: &hir::Local<'_>) { self.print_pat(loc.pat); if let Some(ty) = loc.ty { self.word_space(":"); @@ -1569,11 +1570,11 @@ impl<'a> State<'a> { } } - pub fn print_name(&mut self, name: Symbol) { + fn print_name(&mut self, name: Symbol) { self.print_ident(Ident::with_dummy_span(name)) } - pub fn print_path(&mut self, path: &hir::Path<'_, R>, colons_before_params: bool) { + fn print_path(&mut self, path: &hir::Path<'_, R>, colons_before_params: bool) { self.maybe_print_comment(path.span.lo()); for (i, segment) in path.segments.iter().enumerate() { @@ -1587,14 +1588,14 @@ impl<'a> State<'a> { } } - pub fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) { + fn print_path_segment(&mut self, segment: &hir::PathSegment<'_>) { if segment.ident.name != kw::PathRoot { self.print_ident(segment.ident); self.print_generic_args(segment.args(), false); } } - pub fn print_qpath(&mut self, qpath: &hir::QPath<'_>, colons_before_params: bool) { + fn print_qpath(&mut self, qpath: &hir::QPath<'_>, colons_before_params: bool) { match *qpath { hir::QPath::Resolved(None, path) => self.print_path(path, colons_before_params), hir::QPath::Resolved(Some(qself), path) => { @@ -1711,7 +1712,7 @@ impl<'a> State<'a> { } } - pub fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) { + fn print_type_binding(&mut self, binding: &hir::TypeBinding<'_>) { self.print_ident(binding.ident); self.print_generic_args(binding.gen_args, false); self.space(); @@ -1729,7 +1730,7 @@ impl<'a> State<'a> { } } - pub fn print_pat(&mut self, pat: &hir::Pat<'_>) { + fn print_pat(&mut self, pat: &hir::Pat<'_>) { self.maybe_print_comment(pat.span.lo()); self.ann.pre(self, AnnNode::Pat(pat)); // Pat isn't normalized, but the beauty of it @@ -1873,7 +1874,7 @@ impl<'a> State<'a> { self.ann.post(self, AnnNode::Pat(pat)) } - pub fn print_patfield(&mut self, field: &hir::PatField<'_>) { + fn print_patfield(&mut self, field: &hir::PatField<'_>) { if self.attrs(field.hir_id).is_empty() { self.space(); } @@ -1887,12 +1888,12 @@ impl<'a> State<'a> { self.end(); } - pub fn print_param(&mut self, arg: &hir::Param<'_>) { + fn print_param(&mut self, arg: &hir::Param<'_>) { self.print_outer_attributes(self.attrs(arg.hir_id)); self.print_pat(arg.pat); } - pub fn print_arm(&mut self, arm: &hir::Arm<'_>) { + fn print_arm(&mut self, arm: &hir::Arm<'_>) { // I have no idea why this check is necessary, but here it // is :( if self.attrs(arm.hir_id).is_empty() { @@ -1944,7 +1945,7 @@ impl<'a> State<'a> { self.end() // close enclosing cbox } - pub fn print_fn( + fn print_fn( &mut self, decl: &hir::FnDecl<'_>, header: hir::FnHeader, @@ -2024,14 +2025,14 @@ impl<'a> State<'a> { } } - pub fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) { + fn print_capture_clause(&mut self, capture_clause: hir::CaptureBy) { match capture_clause { hir::CaptureBy::Value => self.word_space("move"), hir::CaptureBy::Ref => {} } } - pub fn print_closure_binder( + fn print_closure_binder( &mut self, binder: hir::ClosureBinder, generic_params: &[GenericParam<'_>], @@ -2067,7 +2068,7 @@ impl<'a> State<'a> { } } - pub fn print_bounds<'b>( + fn print_bounds<'b>( &mut self, prefix: &'static str, bounds: impl IntoIterator>, @@ -2105,7 +2106,7 @@ impl<'a> State<'a> { } } - pub fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) { + fn print_generic_params(&mut self, generic_params: &[GenericParam<'_>]) { if !generic_params.is_empty() { self.word("<"); @@ -2115,7 +2116,7 @@ impl<'a> State<'a> { } } - pub fn print_generic_param(&mut self, param: &GenericParam<'_>) { + fn print_generic_param(&mut self, param: &GenericParam<'_>) { if let GenericParamKind::Const { .. } = param.kind { self.word_space("const"); } @@ -2143,11 +2144,11 @@ impl<'a> State<'a> { } } - pub fn print_lifetime(&mut self, lifetime: &hir::Lifetime) { + fn print_lifetime(&mut self, lifetime: &hir::Lifetime) { self.print_ident(lifetime.ident) } - pub fn print_where_clause(&mut self, generics: &hir::Generics<'_>) { + fn print_where_clause(&mut self, generics: &hir::Generics<'_>) { if generics.predicates.is_empty() { return; } @@ -2204,7 +2205,7 @@ impl<'a> State<'a> { } } - pub fn print_mutability(&mut self, mutbl: hir::Mutability, print_const: bool) { + fn print_mutability(&mut self, mutbl: hir::Mutability, print_const: bool) { match mutbl { hir::Mutability::Mut => self.word_nbsp("mut"), hir::Mutability::Not => { @@ -2215,12 +2216,12 @@ impl<'a> State<'a> { } } - pub fn print_mt(&mut self, mt: &hir::MutTy<'_>, print_const: bool) { + fn print_mt(&mut self, mt: &hir::MutTy<'_>, print_const: bool) { self.print_mutability(mt.mutbl, print_const); self.print_type(mt.ty); } - pub fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) { + fn print_fn_output(&mut self, decl: &hir::FnDecl<'_>) { if let hir::FnRetTy::DefaultReturn(..) = decl.output { return; } @@ -2239,7 +2240,7 @@ impl<'a> State<'a> { } } - pub fn print_ty_fn( + fn print_ty_fn( &mut self, abi: Abi, unsafety: hir::Unsafety, @@ -2267,7 +2268,7 @@ impl<'a> State<'a> { self.end(); } - pub fn print_fn_header_info(&mut self, header: hir::FnHeader) { + fn print_fn_header_info(&mut self, header: hir::FnHeader) { self.print_constness(header.constness); match header.asyncness { @@ -2285,21 +2286,21 @@ impl<'a> State<'a> { self.word("fn") } - pub fn print_constness(&mut self, s: hir::Constness) { + fn print_constness(&mut self, s: hir::Constness) { match s { hir::Constness::NotConst => {} hir::Constness::Const => self.word_nbsp("const"), } } - pub fn print_unsafety(&mut self, s: hir::Unsafety) { + fn print_unsafety(&mut self, s: hir::Unsafety) { match s { hir::Unsafety::Normal => {} hir::Unsafety::Unsafe => self.word_nbsp("unsafe"), } } - pub fn print_is_auto(&mut self, s: hir::IsAuto) { + fn print_is_auto(&mut self, s: hir::IsAuto) { match s { hir::IsAuto::Yes => self.word_nbsp("auto"), hir::IsAuto::No => {} From 494bc8514aa98b7f4786b66a7774004902ef4aa2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 14:14:13 +1100 Subject: [PATCH 18/52] Tweak comments. - Remove an out-of-date comment. (There is no `PpAnn` implementation for `hir::Crate`.) - Remove a low-value comment. - And break a very long comment. --- compiler/rustc_hir_pretty/src/lib.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index e6388f34eea24..077f9e947e685 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -52,8 +52,6 @@ pub struct NoAnn; impl PpAnn for NoAnn {} pub const NO_ANN: &dyn PpAnn = &NoAnn; -/// Identical to the `PpAnn` implementation for `hir::Crate`, -/// except it avoids creating a dependency on the whole crate. impl PpAnn for &dyn rustc_hir::intravisit::Map<'_> { fn nested(&self, state: &mut State<'_>, nested: Nested) { match nested { @@ -446,7 +444,6 @@ impl<'a> State<'a> { self.end(); // end the outer ibox } - /// Pretty-print an item fn print_item(&mut self, item: &hir::Item<'_>) { self.hardbreak_if_not_bol(); self.maybe_print_comment(item.span.lo()); @@ -2052,7 +2049,8 @@ impl<'a> State<'a> { match binder { hir::ClosureBinder::Default => {} - // we need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional restrictions + // We need to distinguish `|...| {}` from `for<> |...| {}` as `for<>` adds additional + // restrictions. hir::ClosureBinder::For { .. } if generic_params.is_empty() => self.word("for<>"), hir::ClosureBinder::For { .. } => { self.word("for"); From 7d35902c6275f5236f77427c2cca8d58f8f8a579 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 14:23:08 +1100 Subject: [PATCH 19/52] Fiddle with `State` functions. Remove and inline `new_from_input`, because it has a single call site. And move `attrs` into the earlier `impl` block. --- compiler/rustc_hir_pretty/src/lib.rs | 32 +++++++++------------------- 1 file changed, 10 insertions(+), 22 deletions(-) diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 077f9e947e685..ab6ab391484f3 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -73,6 +73,10 @@ pub struct State<'a> { } impl<'a> State<'a> { + fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] { + (self.attrs)(id) + } + fn print_node(&mut self, node: Node<'_>) { match node { Node::Param(a) => self.print_param(a), @@ -154,7 +158,12 @@ pub fn print_crate<'a>( attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute], ann: &'a dyn PpAnn, ) -> String { - let mut s = State::new_from_input(sm, filename, input, attrs, ann); + let mut s = State { + s: pp::Printer::new(), + comments: Some(Comments::new(sm, filename, input)), + attrs, + ann, + }; // When printing the AST, we sometimes need to inject `#[no_std]` here. // Since you can't compile the HIR, it's not necessary. @@ -164,27 +173,6 @@ pub fn print_crate<'a>( s.s.eof() } -impl<'a> State<'a> { - fn new_from_input( - sm: &'a SourceMap, - filename: FileName, - input: String, - attrs: &'a dyn Fn(hir::HirId) -> &'a [ast::Attribute], - ann: &'a dyn PpAnn, - ) -> State<'a> { - State { - s: pp::Printer::new(), - comments: Some(Comments::new(sm, filename, input)), - attrs, - ann, - } - } - - fn attrs(&self, id: hir::HirId) -> &'a [ast::Attribute] { - (self.attrs)(id) - } -} - fn to_string(ann: &dyn PpAnn, f: F) -> String where F: FnOnce(&mut State<'_>), From 232aaeba7c6779233659b0a57ed75a5d7a48cfb0 Mon Sep 17 00:00:00 2001 From: Georg Semmler Date: Wed, 11 Oct 2023 21:57:53 +0200 Subject: [PATCH 20/52] Handle several `#[diagnostic::on_unimplemented]` attributes correctly This PR fixes an issues where rustc would ignore subsequent `#[diagnostic::on_unimplemented]` attributes. The [corresponding RFC](https://rust-lang.github.io/rfcs/3368-diagnostic-attribute-namespace.html) specifies that the first matching instance of each option is used. Invalid attributes are linted and otherwise ignored. --- .../error_reporting/on_unimplemented.rs | 46 +++++++++++----- ...ed_options_and_continue_to_use_fallback.rs | 22 ++++++++ ...ptions_and_continue_to_use_fallback.stderr | 52 +++++++++++++++++++ 3 files changed, 108 insertions(+), 12 deletions(-) create mode 100644 tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs create mode 100644 tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr 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 d9059e46a8c55..cc1f13a2f0f22 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 @@ -1,6 +1,6 @@ use super::{ObligationCauseCode, PredicateObligation}; use crate::infer::error_reporting::TypeErrCtxt; -use rustc_ast::{MetaItem, NestedMetaItem}; +use rustc_ast::{Attribute, MetaItem, NestedMetaItem}; use rustc_attr as attr; use rustc_data_structures::fx::FxHashMap; use rustc_errors::{struct_span_err, ErrorGuaranteed}; @@ -474,18 +474,40 @@ impl<'tcx> OnUnimplementedDirective { } pub fn of_item(tcx: TyCtxt<'tcx>, item_def_id: DefId) -> Result, ErrorGuaranteed> { - let mut is_diagnostic_namespace_variant = false; - let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented).or_else(|| { - if tcx.features().diagnostic_namespace { - is_diagnostic_namespace_variant = true; - tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented]).next() - } else { - None - } - }) else { - return Ok(None); - }; + if let Some(attr) = tcx.get_attr(item_def_id, sym::rustc_on_unimplemented) { + return Self::parse_attribute(attr, false, tcx, item_def_id); + } else if tcx.features().diagnostic_namespace { + tcx.get_attrs_by_path(item_def_id, &[sym::diagnostic, sym::on_unimplemented]) + .filter_map(|attr| Self::parse_attribute(attr, true, tcx, item_def_id).transpose()) + .try_fold(None, |aggr: Option, directive| { + let directive = directive?; + if let Some(aggr) = aggr { + let mut subcommands = aggr.subcommands; + subcommands.extend(directive.subcommands); + Ok(Some(Self { + condition: aggr.condition.or(directive.condition), + subcommands, + message: aggr.message.or(directive.message), + label: aggr.label.or(directive.label), + note: aggr.note.or(directive.note), + parent_label: aggr.parent_label.or(directive.parent_label), + append_const_msg: aggr.append_const_msg.or(directive.append_const_msg), + })) + } else { + Ok(Some(directive)) + } + }) + } else { + Ok(None) + } + } + fn parse_attribute( + attr: &Attribute, + is_diagnostic_namespace_variant: bool, + tcx: TyCtxt<'tcx>, + item_def_id: DefId, + ) -> Result, ErrorGuaranteed> { let result = if let Some(items) = attr.meta_item_list() { Self::parse(tcx, item_def_id, &items, attr.span, true, is_diagnostic_namespace_variant) } else if let Some(value) = attr.value_str() { diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs new file mode 100644 index 0000000000000..353075863918c --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.rs @@ -0,0 +1,22 @@ +#![feature(diagnostic_namespace)] + +#[diagnostic::on_unimplemented( + //~^WARN malformed `on_unimplemented` attribute + //~|WARN malformed `on_unimplemented` attribute + if(Self = ()), + message = "not used yet", + label = "not used yet", + note = "not used yet" +)] +#[diagnostic::on_unimplemented(message = "fallback!!")] +#[diagnostic::on_unimplemented(label = "fallback label")] +#[diagnostic::on_unimplemented(note = "fallback note")] +#[diagnostic::on_unimplemented(message = "fallback2!!")] +trait Foo {} + +fn takes_foo(_: impl Foo) {} + +fn main() { + takes_foo(()); + //~^ERROR fallback!! +} diff --git a/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr new file mode 100644 index 0000000000000..6a83d8e39c656 --- /dev/null +++ b/tests/ui/diagnostic_namespace/on_unimplemented/ignore_unsupported_options_and_continue_to_use_fallback.stderr @@ -0,0 +1,52 @@ +warning: malformed `on_unimplemented` attribute + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1 + | +LL | / #[diagnostic::on_unimplemented( +LL | | +LL | | +LL | | if(Self = ()), +... | +LL | | note = "not used yet" +LL | | )] + | |__^ + | + = note: `#[warn(unknown_or_malformed_diagnostic_attributes)]` on by default + +warning: malformed `on_unimplemented` attribute + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:3:1 + | +LL | / #[diagnostic::on_unimplemented( +LL | | +LL | | +LL | | if(Self = ()), +... | +LL | | note = "not used yet" +LL | | )] + | |__^ + | + = note: duplicate diagnostic emitted due to `-Z deduplicate-diagnostics=no` + +error[E0277]: fallback!! + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:20:15 + | +LL | takes_foo(()); + | --------- ^^ fallback label + | | + | required by a bound introduced by this call + | + = help: the trait `Foo` is not implemented for `()` + = note: fallback note +help: this trait has no implementations, consider adding one + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:15:1 + | +LL | trait Foo {} + | ^^^^^^^^^ +note: required by a bound in `takes_foo` + --> $DIR/ignore_unsupported_options_and_continue_to_use_fallback.rs:17:22 + | +LL | fn takes_foo(_: impl Foo) {} + | ^^^ required by this bound in `takes_foo` + +error: aborting due to previous error; 2 warnings emitted + +For more information about this error, try `rustc --explain E0277`. From becf4942a26288916302f9a5f3fc6d4cc88abae8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 8 Aug 2023 11:34:07 +1000 Subject: [PATCH 21/52] Rename `Token::is_op` as `Token::is_punct`. For consistency with `proc_macro::Punct`. --- compiler/rustc_ast/src/token.rs | 2 +- compiler/rustc_parse/src/lexer/tokentrees.rs | 7 +++++-- compiler/rustc_parse/src/parser/expr.rs | 2 +- 3 files changed, 7 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast/src/token.rs b/compiler/rustc_ast/src/token.rs index 09bfbd02198c0..2de398521f57b 100644 --- a/compiler/rustc_ast/src/token.rs +++ b/compiler/rustc_ast/src/token.rs @@ -404,7 +404,7 @@ impl Token { [DotDot, DotDotDot, DotDotEq].contains(&self.kind) } - pub fn is_op(&self) -> bool { + pub fn is_punct(&self) -> bool { match self.kind { Eq | Lt | Le | EqEq | Ne | Ge | Gt | AndAnd | OrOr | Not | Tilde | BinOp(_) | BinOpEq(_) | At | Dot | DotDot | DotDotDot | DotDotEq | Comma | Semi | Colon diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 07910113dee7f..7cdb197047099 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -59,8 +59,11 @@ impl<'a> TokenTreesReader<'a> { if let Some(glued) = self.token.glue(&next_tok) { self.token = glued; } else { - let this_spacing = - if next_tok.is_op() { Spacing::Joint } else { Spacing::Alone }; + let this_spacing = if next_tok.is_punct() { + Spacing::Joint + } else { + Spacing::Alone + }; break (this_spacing, next_tok); } } else { diff --git a/compiler/rustc_parse/src/parser/expr.rs b/compiler/rustc_parse/src/parser/expr.rs index 91bb2d9eb666f..1d883e16f9dc7 100644 --- a/compiler/rustc_parse/src/parser/expr.rs +++ b/compiler/rustc_parse/src/parser/expr.rs @@ -1592,7 +1592,7 @@ impl<'a> Parser<'a> { } else if !ate_colon && self.may_recover() && (matches!(self.token.kind, token::CloseDelim(_) | token::Comma) - || self.token.is_op()) + || self.token.is_punct()) { let (lit, _) = self.recover_unclosed_char(label_.ident, Parser::mk_token_lit_char, |self_| { From 129fe9a998e611f3b16da9156934fc78149e0860 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 8 Aug 2023 11:28:29 +1000 Subject: [PATCH 22/52] Add a comment to `tests/ui/proc-macro/issue-75930-derive-cfg.rs`. Explaining something in the output that surprised me. --- tests/ui/proc-macro/issue-75930-derive-cfg.rs | 30 + .../proc-macro/issue-75930-derive-cfg.stderr | 4 +- .../proc-macro/issue-75930-derive-cfg.stdout | 768 +++++++++--------- 3 files changed, 416 insertions(+), 386 deletions(-) diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.rs b/tests/ui/proc-macro/issue-75930-derive-cfg.rs index ef56e8e02d0c4..e0213527c5005 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.rs +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.rs @@ -16,6 +16,36 @@ extern crate std; #[macro_use] extern crate test_macros; +// Note: the expected output contains this sequence: +// ``` +// Punct { +// ch: '<', +// spacing: Joint, +// span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:12 (#0), +// }, +// Ident { +// ident: "B", +// span: $DIR/issue-75930-derive-cfg.rs:25:29: 25:30 (#0), +// }, +// ``` +// It's surprising to see a `Joint` token tree followed by an `Ident` token +// tree, because `Joint` is supposed to only be used if the following token is +// `Punct`. +// +// It is because of this code from below: +// ``` +// struct Foo<#[cfg(FALSE)] A, B> +// ``` +// When the token stream is formed during parsing, `<` is followed immediately +// by `#`, which is punctuation, so it is marked `Joint`. But before being +// passed to the proc macro it is rewritten to this: +// ``` +// struct Foo +// ``` +// But the `Joint` marker on the `<` is not updated. Perhaps it should be +// corrected before being passed to the proc macro? But a prior attempt to do +// that kind of correction caused the problem seen in #76399, so maybe not. + #[print_helper(a)] //~ WARN derive helper attribute is used before it is introduced //~| WARN this was previously accepted #[cfg_attr(not(FALSE), allow(dead_code))] diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stderr b/tests/ui/proc-macro/issue-75930-derive-cfg.stderr index f3f470676e406..1017745de6f2b 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.stderr +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stderr @@ -1,5 +1,5 @@ warning: derive helper attribute is used before it is introduced - --> $DIR/issue-75930-derive-cfg.rs:19:3 + --> $DIR/issue-75930-derive-cfg.rs:49:3 | LL | #[print_helper(a)] | ^^^^^^^^^^^^ @@ -12,7 +12,7 @@ LL | #[derive(Print)] = note: `#[warn(legacy_derive_helpers)]` on by default warning: derive helper attribute is used before it is introduced - --> $DIR/issue-75930-derive-cfg.rs:19:3 + --> $DIR/issue-75930-derive-cfg.rs:49:3 | LL | #[print_helper(a)] | ^^^^^^^^^^^^ diff --git a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout index 83afd0d3eaec3..31a1c44b6df04 100644 --- a/tests/ui/proc-macro/issue-75930-derive-cfg.stdout +++ b/tests/ui/proc-macro/issue-75930-derive-cfg.stdout @@ -26,158 +26,158 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:1: 49:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:19:3: 19:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:3: 49:15 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "a", - span: $DIR/issue-75930-derive-cfg.rs:19:16: 19:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:16: 49:17 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:19:15: 19:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:15: 49:18 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:19:2: 19:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:2: 49:19 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "allow", - span: $DIR/issue-75930-derive-cfg.rs:21:24: 21:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:24: 51:29 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "dead_code", - span: $DIR/issue-75930-derive-cfg.rs:21:30: 21:39 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:30: 51:39 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:21:29: 21:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:29: 51:40 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:23:1: 23:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:53:1: 53:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "derive", - span: $DIR/issue-75930-derive-cfg.rs:23:3: 23:9 (#0), + span: $DIR/issue-75930-derive-cfg.rs:53:3: 53:9 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "Print", - span: $DIR/issue-75930-derive-cfg.rs:23:10: 23:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:53:10: 53:15 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:23:9: 23:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:53:9: 53:16 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:23:2: 23:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:53:2: 53:17 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:24:1: 24:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:1: 54:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:24:3: 24:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:3: 54:15 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "b", - span: $DIR/issue-75930-derive-cfg.rs:24:16: 24:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:16: 54:17 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:15: 54:18 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:24:2: 24:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:2: 54:19 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:25:1: 25:7 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:1: 55:7 (#0), }, Ident { ident: "Foo", - span: $DIR/issue-75930-derive-cfg.rs:25:8: 25:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:8: 55:11 (#0), }, Punct { ch: '<', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:12 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:11: 55:12 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:25:12: 25:13 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:12: 55:13 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:25:14: 25:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:14: 55:17 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:25:18: 25:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:18: 55:23 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:25:17: 25:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:17: 55:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:25:13: 25:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:13: 55:25 (#0), }, Ident { ident: "A", - span: $DIR/issue-75930-derive-cfg.rs:25:26: 25:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:26: 55:27 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:25:27: 25:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:27: 55:28 (#0), }, Ident { ident: "B", - span: $DIR/issue-75930-derive-cfg.rs:25:29: 25:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:29: 55:30 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:25:30: 25:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:30: 55:31 (#0), }, Group { delimiter: Brace, @@ -185,128 +185,128 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:26:5: 26:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:5: 56:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:26:7: 26:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:7: 56:10 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:26:11: 26:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:11: 56:16 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:26:10: 26:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:10: 56:17 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:26:6: 26:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:6: 56:18 (#0), }, Ident { ident: "first", - span: $DIR/issue-75930-derive-cfg.rs:26:19: 26:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:19: 56:24 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:26:24: 26:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:24: 56:25 (#0), }, Ident { ident: "String", - span: $DIR/issue-75930-derive-cfg.rs:26:26: 26:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:26: 56:32 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:26:32: 26:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:56:32: 56:33 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:5: 27:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:5: 57:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg_attr", - span: $DIR/issue-75930-derive-cfg.rs:27:7: 27:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:7: 57:15 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:27:16: 27:21 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:16: 57:21 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:21: 27:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:21: 57:22 (#0), }, Ident { ident: "deny", - span: $DIR/issue-75930-derive-cfg.rs:27:23: 27:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:23: 57:27 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "warnings", - span: $DIR/issue-75930-derive-cfg.rs:27:28: 27:36 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:28: 57:36 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:27:27: 27:37 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:27: 57:37 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:27:15: 27:38 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:15: 57:38 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:27:6: 27:39 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:6: 57:39 (#0), }, Ident { ident: "second", - span: $DIR/issue-75930-derive-cfg.rs:27:40: 27:46 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:40: 57:46 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:46: 27:47 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:46: 57:47 (#0), }, Ident { ident: "bool", - span: $DIR/issue-75930-derive-cfg.rs:27:48: 27:52 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:48: 57:52 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:52: 27:53 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:52: 57:53 (#0), }, Ident { ident: "third", - span: $DIR/issue-75930-derive-cfg.rs:28:5: 28:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:5: 58:10 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:28:10: 28:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:10: 58:11 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:28:13: 28:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:13: 58:15 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:16 (#0), }, Group { delimiter: Brace, @@ -314,145 +314,145 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:29:9: 29:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:9: 59:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:29:11: 29:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:11: 59:14 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:29:15: 29:20 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:15: 59:20 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:29:14: 29:21 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:14: 59:21 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:29:10: 29:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:10: 59:22 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:29:23: 29:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:23: 59:29 (#0), }, Ident { ident: "Bar", - span: $DIR/issue-75930-derive-cfg.rs:29:30: 29:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:30: 59:33 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:29:33: 29:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:59:33: 59:34 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:30:9: 30:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:9: 60:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:30:11: 30:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:11: 60:14 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:30:19: 30:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:19: 60:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:18: 30:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:18: 60:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:14: 60:26 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:10: 30:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:10: 60:27 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:30:28: 30:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:28: 60:34 (#0), }, Ident { ident: "Inner", - span: $DIR/issue-75930-derive-cfg.rs:30:35: 30:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:35: 60:40 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:30:40: 30:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:40: 60:41 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:31:9: 31:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:9: 61:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:31:11: 31:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:11: 61:14 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:31:15: 31:20 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:15: 61:20 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:31:14: 31:21 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:14: 61:21 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:31:10: 31:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:10: 61:22 (#0), }, Ident { ident: "let", - span: $DIR/issue-75930-derive-cfg.rs:31:23: 31:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:23: 61:26 (#0), }, Ident { ident: "a", - span: $DIR/issue-75930-derive-cfg.rs:31:27: 31:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:27: 61:28 (#0), }, Punct { ch: '=', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:31:29: 31:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:29: 61:30 (#0), }, Literal { kind: Integer, symbol: "25", suffix: None, - span: $DIR/issue-75930-derive-cfg.rs:31:31: 31:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:31: 61:33 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:31:33: 31:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:61:33: 61:34 (#0), }, Ident { ident: "match", - span: $DIR/issue-75930-derive-cfg.rs:32:9: 32:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:9: 62:14 (#0), }, Ident { ident: "true", - span: $DIR/issue-75930-derive-cfg.rs:32:15: 32:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:15: 62:19 (#0), }, Group { delimiter: Brace, @@ -460,194 +460,194 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:33:13: 33:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:13: 63:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:33:15: 33:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:15: 63:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:33:19: 33:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:19: 63:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:33:18: 33:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:18: 63:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:33:14: 33:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:14: 63:26 (#0), }, Ident { ident: "true", - span: $DIR/issue-75930-derive-cfg.rs:33:27: 33:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:27: 63:31 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:33:32: 33:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:32: 63:33 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:33:33: 33:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:33: 63:34 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:33:35: 33:37 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:35: 63:37 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:33:37: 33:38 (#0), + span: $DIR/issue-75930-derive-cfg.rs:63:37: 63:38 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:13: 34:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:13: 64:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg_attr", - span: $DIR/issue-75930-derive-cfg.rs:34:15: 34:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:15: 64:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:34:24: 34:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:24: 64:27 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:34:28: 34:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:28: 64:33 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:27: 34:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:27: 64:34 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:34: 34:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:34: 64:35 (#0), }, Ident { ident: "allow", - span: $DIR/issue-75930-derive-cfg.rs:34:36: 34:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:36: 64:41 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "warnings", - span: $DIR/issue-75930-derive-cfg.rs:34:42: 34:50 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:42: 64:50 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:41: 34:51 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:41: 64:51 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:23: 34:52 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:23: 64:52 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:14: 34:53 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:14: 64:53 (#0), }, Ident { ident: "false", - span: $DIR/issue-75930-derive-cfg.rs:34:54: 34:59 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:54: 64:59 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:34:60: 34:61 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:60: 64:61 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:61: 34:62 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:61: 64:62 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:34:63: 34:65 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:63: 64:65 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:65: 34:66 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:65: 64:66 (#0), }, Ident { ident: "_", - span: $DIR/issue-75930-derive-cfg.rs:35:13: 35:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:13: 65:14 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:35:15: 35:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:15: 65:16 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:35:16: 35:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:16: 65:17 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:35:18: 35:20 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:18: 65:20 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:32:20: 36:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:20: 66:10 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:36:10: 36:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:66:10: 66:11 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:38:9: 38:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:68:9: 68:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:38:11: 38:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:68:11: 68:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "should_be_removed", - span: $DIR/issue-75930-derive-cfg.rs:38:24: 38:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:68:24: 68:41 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:38:23: 38:42 (#0), + span: $DIR/issue-75930-derive-cfg.rs:68:23: 68:42 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:38:10: 38:43 (#0), + span: $DIR/issue-75930-derive-cfg.rs:68:10: 68:43 (#0), }, Ident { ident: "fn", - span: $DIR/issue-75930-derive-cfg.rs:39:9: 39:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:69:9: 69:11 (#0), }, Ident { ident: "removed_fn", - span: $DIR/issue-75930-derive-cfg.rs:39:12: 39:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:69:12: 69:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:39:22: 39:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:69:22: 69:24 (#0), }, Group { delimiter: Brace, @@ -655,108 +655,108 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:40:13: 40:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:13: 70:14 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:40:14: 40:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:14: 70:15 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:40:16: 40:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:16: 70:19 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:40:20: 40:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:20: 70:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:40:19: 40:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:19: 70:26 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:40:15: 40:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:70:15: 70:27 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:39:25: 41:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:69:25: 71:10 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:43:9: 43:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:9: 73:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:43:11: 43:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:11: 73:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "c", - span: $DIR/issue-75930-derive-cfg.rs:43:24: 43:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:24: 73:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:23: 43:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:23: 73:26 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:10: 43:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:10: 73:27 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:43:28: 43:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:28: 73:29 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:43:30: 43:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:30: 73:33 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:43:34: 43:37 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:34: 73:37 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:43:38: 43:43 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:38: 73:43 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:37: 43:44 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:37: 73:44 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:33: 43:45 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:33: 73:45 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:29: 43:46 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:29: 73:46 (#0), }, Ident { ident: "fn", - span: $DIR/issue-75930-derive-cfg.rs:43:47: 43:49 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:47: 73:49 (#0), }, Ident { ident: "kept_fn", - span: $DIR/issue-75930-derive-cfg.rs:43:50: 43:57 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:50: 73:57 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:43:57: 43:59 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:57: 73:59 (#0), }, Group { delimiter: Brace, @@ -764,82 +764,82 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:44:13: 44:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:13: 74:14 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:44:14: 44:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:14: 74:15 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:44:16: 44:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:16: 74:19 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:44:20: 44:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:20: 74:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:44:24: 44:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:24: 74:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:23: 44:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:23: 74:30 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:19: 44:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:19: 74:31 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:15: 44:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:15: 74:32 (#0), }, Ident { ident: "let", - span: $DIR/issue-75930-derive-cfg.rs:45:13: 45:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:13: 75:16 (#0), }, Ident { ident: "my_val", - span: $DIR/issue-75930-derive-cfg.rs:45:17: 45:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:17: 75:23 (#0), }, Punct { ch: '=', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:45:24: 45:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:24: 75:25 (#0), }, Ident { ident: "true", - span: $DIR/issue-75930-derive-cfg.rs:45:26: 45:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:26: 75:30 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:45:30: 45:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:30: 75:31 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:60: 46:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:60: 76:10 (#0), }, Ident { ident: "enum", - span: $DIR/issue-75930-derive-cfg.rs:48:9: 48:13 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:9: 78:13 (#0), }, Ident { ident: "TupleEnum", - span: $DIR/issue-75930-derive-cfg.rs:48:14: 48:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:14: 78:23 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "Foo", - span: $DIR/issue-75930-derive-cfg.rs:49:13: 49:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:79:13: 79:16 (#0), }, Group { delimiter: Parenthesis, @@ -847,166 +847,166 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:50:17: 50:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:17: 80:18 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:50:19: 50:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:19: 80:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:50:23: 50:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:23: 80:28 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:50:22: 50:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:22: 80:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:50:18: 50:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:18: 80:30 (#0), }, Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:50:31: 50:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:31: 80:33 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:50:33: 50:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:80:33: 80:34 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:51:17: 51:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:17: 81:18 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:51:19: 51:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:19: 81:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:51:23: 51:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:23: 81:28 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:51:22: 51:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:22: 81:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:51:18: 51:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:18: 81:30 (#0), }, Ident { ident: "bool", - span: $DIR/issue-75930-derive-cfg.rs:51:31: 51:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:31: 81:35 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:51:35: 51:36 (#0), + span: $DIR/issue-75930-derive-cfg.rs:81:35: 81:36 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:52:17: 52:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:17: 82:18 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:52:19: 52:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:19: 82:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:52:23: 52:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:23: 82:26 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:52:27: 52:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:27: 82:32 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:26: 52:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:26: 82:33 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:22: 52:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:22: 82:34 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:18: 52:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:18: 82:35 (#0), }, Ident { ident: "i32", - span: $DIR/issue-75930-derive-cfg.rs:52:36: 52:39 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:36: 82:39 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:52:39: 52:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:39: 82:40 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:53:17: 53:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:17: 83:18 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:53:19: 53:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:19: 83:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:53:23: 53:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:23: 83:28 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:53:22: 53:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:22: 83:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:53:18: 53:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:18: 83:30 (#0), }, Ident { ident: "String", - span: $DIR/issue-75930-derive-cfg.rs:53:31: 53:37 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:31: 83:37 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:53:37: 53:38 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:37: 83:38 (#0), }, Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:53:39: 53:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:39: 83:41 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:49:16: 54:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:79:16: 84:14 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:48:24: 55:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:24: 85:10 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:57:9: 57:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:9: 87:15 (#0), }, Ident { ident: "TupleStruct", - span: $DIR/issue-75930-derive-cfg.rs:57:16: 57:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:16: 87:27 (#0), }, Group { delimiter: Parenthesis, @@ -1014,139 +1014,139 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:58:13: 58:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:13: 88:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:15: 88:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:58:19: 58:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:19: 88:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:58:18: 58:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:18: 88:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:58:14: 58:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:14: 88:26 (#0), }, Ident { ident: "String", - span: $DIR/issue-75930-derive-cfg.rs:58:27: 58:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:27: 88:33 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:58:33: 58:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:88:33: 88:34 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:59:13: 59:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:13: 89:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:59:15: 59:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:15: 89:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:59:19: 59:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:19: 89:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:59:23: 59:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:23: 89:28 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:22: 59:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:22: 89:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:18: 59:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:18: 89:30 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:14: 59:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:14: 89:31 (#0), }, Ident { ident: "i32", - span: $DIR/issue-75930-derive-cfg.rs:59:32: 59:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:32: 89:35 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:59:35: 59:36 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:35: 89:36 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:60:13: 60:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:13: 90:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:15: 90:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:60:19: 60:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:19: 90:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:60:18: 60:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:18: 90:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:60:14: 60:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:14: 90:26 (#0), }, Ident { ident: "bool", - span: $DIR/issue-75930-derive-cfg.rs:60:27: 60:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:27: 90:31 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:60:31: 60:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:90:31: 90:32 (#0), }, Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:61:13: 61:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:91:13: 91:15 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:57:27: 62:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:27: 92:10 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:62:10: 62:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:92:10: 92:11 (#0), }, Ident { ident: "fn", - span: $DIR/issue-75930-derive-cfg.rs:64:9: 64:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:94:9: 94:11 (#0), }, Ident { ident: "plain_removed_fn", - span: $DIR/issue-75930-derive-cfg.rs:64:12: 64:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:94:12: 94:28 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:64:28: 64:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:94:28: 94:30 (#0), }, Group { delimiter: Brace, @@ -1154,122 +1154,122 @@ PRINT-ATTR INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:65:13: 65:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:13: 95:14 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:65:14: 65:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:14: 95:15 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg_attr", - span: $DIR/issue-75930-derive-cfg.rs:65:16: 65:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:16: 95:24 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:65:25: 65:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:25: 95:28 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:65:29: 65:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:29: 95:34 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:65:28: 65:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:28: 95:35 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:65:35: 65:36 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:35: 95:36 (#0), }, Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:65:37: 65:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:37: 95:40 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:65:41: 65:46 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:41: 95:46 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:65:40: 65:47 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:40: 95:47 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:65:24: 65:48 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:24: 95:48 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:65:15: 65:49 (#0), + span: $DIR/issue-75930-derive-cfg.rs:95:15: 95:49 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:64:31: 66:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:94:31: 96:10 (#0), }, Literal { kind: Integer, symbol: "0", suffix: None, - span: $DIR/issue-75930-derive-cfg.rs:68:9: 68:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:98:9: 98:10 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:28:17: 69:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:17: 99:6 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:28:12: 69:7 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:12: 99:7 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:69:7: 69:8 (#0), + span: $DIR/issue-75930-derive-cfg.rs:99:7: 99:8 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:70:5: 70:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:5: 100:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:70:7: 70:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:7: 100:19 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "d", - span: $DIR/issue-75930-derive-cfg.rs:70:20: 70:21 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:20: 100:21 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:70:19: 70:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:19: 100:22 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:70:6: 70:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:6: 100:23 (#0), }, Ident { ident: "fourth", - span: $DIR/issue-75930-derive-cfg.rs:71:5: 71:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:5: 101:11 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:71:11: 71:12 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:11: 101:12 (#0), }, Ident { ident: "B", - span: $DIR/issue-75930-derive-cfg.rs:71:13: 71:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:13: 101:14 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:25:32: 72:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:32: 102:2 (#0), }, ] PRINT-DERIVE INPUT (DISPLAY): #[print_helper(a)] #[allow(dead_code)] #[print_helper(b)] struct Foo < B > @@ -1289,141 +1289,141 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:19:1: 19:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:1: 49:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:19:3: 19:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:3: 49:15 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "a", - span: $DIR/issue-75930-derive-cfg.rs:19:16: 19:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:16: 49:17 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:19:15: 19:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:15: 49:18 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:19:2: 19:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:49:2: 49:19 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "allow", - span: $DIR/issue-75930-derive-cfg.rs:21:24: 21:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:24: 51:29 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "dead_code", - span: $DIR/issue-75930-derive-cfg.rs:21:30: 21:39 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:30: 51:39 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:21:29: 21:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:29: 51:40 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:21:1: 21:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:51:1: 51:2 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:24:1: 24:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:1: 54:2 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:24:3: 24:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:3: 54:15 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "b", - span: $DIR/issue-75930-derive-cfg.rs:24:16: 24:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:16: 54:17 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:24:15: 24:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:15: 54:18 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:24:2: 24:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:54:2: 54:19 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:25:1: 25:7 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:1: 55:7 (#0), }, Ident { ident: "Foo", - span: $DIR/issue-75930-derive-cfg.rs:25:8: 25:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:8: 55:11 (#0), }, Punct { ch: '<', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:25:11: 25:12 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:11: 55:12 (#0), }, Ident { ident: "B", - span: $DIR/issue-75930-derive-cfg.rs:25:29: 25:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:29: 55:30 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:25:30: 25:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:30: 55:31 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "second", - span: $DIR/issue-75930-derive-cfg.rs:27:40: 27:46 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:40: 57:46 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:46: 27:47 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:46: 57:47 (#0), }, Ident { ident: "bool", - span: $DIR/issue-75930-derive-cfg.rs:27:48: 27:52 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:48: 57:52 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:27:52: 27:53 (#0), + span: $DIR/issue-75930-derive-cfg.rs:57:52: 57:53 (#0), }, Ident { ident: "third", - span: $DIR/issue-75930-derive-cfg.rs:28:5: 28:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:5: 58:10 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:28:10: 28:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:10: 58:11 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:28:13: 28:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:13: 58:15 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:28:15: 28:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:15: 58:16 (#0), }, Group { delimiter: Brace, @@ -1431,58 +1431,58 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:30:9: 30:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:9: 60:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:30:11: 30:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:11: 60:14 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:30:15: 30:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:15: 60:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:30:19: 30:24 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:19: 60:24 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:18: 30:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:18: 60:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:14: 30:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:14: 60:26 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:30:10: 30:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:10: 60:27 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:30:28: 30:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:28: 60:34 (#0), }, Ident { ident: "Inner", - span: $DIR/issue-75930-derive-cfg.rs:30:35: 30:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:35: 60:40 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:30:40: 30:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:60:40: 60:41 (#0), }, Ident { ident: "match", - span: $DIR/issue-75930-derive-cfg.rs:32:9: 32:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:9: 62:14 (#0), }, Ident { ident: "true", - span: $DIR/issue-75930-derive-cfg.rs:32:15: 32:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:15: 62:19 (#0), }, Group { delimiter: Brace, @@ -1490,151 +1490,151 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:13: 34:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:13: 64:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "allow", - span: $DIR/issue-75930-derive-cfg.rs:34:36: 34:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:36: 64:41 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "warnings", - span: $DIR/issue-75930-derive-cfg.rs:34:42: 34:50 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:42: 64:50 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:41: 34:51 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:41: 64:51 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:34:13: 34:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:13: 64:14 (#0), }, Ident { ident: "false", - span: $DIR/issue-75930-derive-cfg.rs:34:54: 34:59 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:54: 64:59 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:34:60: 34:61 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:60: 64:61 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:61: 34:62 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:61: 64:62 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:34:63: 34:65 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:63: 64:65 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:34:65: 34:66 (#0), + span: $DIR/issue-75930-derive-cfg.rs:64:65: 64:66 (#0), }, Ident { ident: "_", - span: $DIR/issue-75930-derive-cfg.rs:35:13: 35:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:13: 65:14 (#0), }, Punct { ch: '=', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:35:15: 35:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:15: 65:16 (#0), }, Punct { ch: '>', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:35:16: 35:17 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:16: 65:17 (#0), }, Group { delimiter: Brace, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:35:18: 35:20 (#0), + span: $DIR/issue-75930-derive-cfg.rs:65:18: 65:20 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:32:20: 36:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:62:20: 66:10 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:36:10: 36:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:66:10: 66:11 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:43:9: 43:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:9: 73:10 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:43:11: 43:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:11: 73:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "c", - span: $DIR/issue-75930-derive-cfg.rs:43:24: 43:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:24: 73:25 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:23: 43:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:23: 73:26 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:10: 43:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:10: 73:27 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:43:28: 43:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:28: 73:29 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:43:30: 43:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:30: 73:33 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:43:34: 43:37 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:34: 73:37 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:43:38: 43:43 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:38: 73:43 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:37: 43:44 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:37: 73:44 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:33: 43:45 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:33: 73:45 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:29: 43:46 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:29: 73:46 (#0), }, Ident { ident: "fn", - span: $DIR/issue-75930-derive-cfg.rs:43:47: 43:49 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:47: 73:49 (#0), }, Ident { ident: "kept_fn", - span: $DIR/issue-75930-derive-cfg.rs:43:50: 43:57 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:50: 73:57 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [], - span: $DIR/issue-75930-derive-cfg.rs:43:57: 43:59 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:57: 73:59 (#0), }, Group { delimiter: Brace, @@ -1642,82 +1642,82 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Joint, - span: $DIR/issue-75930-derive-cfg.rs:44:13: 44:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:13: 74:14 (#0), }, Punct { ch: '!', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:44:14: 44:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:14: 74:15 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:44:16: 44:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:16: 74:19 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:44:20: 44:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:20: 74:23 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:44:24: 44:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:24: 74:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:23: 44:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:23: 74:30 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:19: 44:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:19: 74:31 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:44:15: 44:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:74:15: 74:32 (#0), }, Ident { ident: "let", - span: $DIR/issue-75930-derive-cfg.rs:45:13: 45:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:13: 75:16 (#0), }, Ident { ident: "my_val", - span: $DIR/issue-75930-derive-cfg.rs:45:17: 45:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:17: 75:23 (#0), }, Punct { ch: '=', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:45:24: 45:25 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:24: 75:25 (#0), }, Ident { ident: "true", - span: $DIR/issue-75930-derive-cfg.rs:45:26: 45:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:26: 75:30 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:45:30: 45:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:75:30: 75:31 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:43:60: 46:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:73:60: 76:10 (#0), }, Ident { ident: "enum", - span: $DIR/issue-75930-derive-cfg.rs:48:9: 48:13 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:9: 78:13 (#0), }, Ident { ident: "TupleEnum", - span: $DIR/issue-75930-derive-cfg.rs:48:14: 48:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:14: 78:23 (#0), }, Group { delimiter: Brace, stream: TokenStream [ Ident { ident: "Foo", - span: $DIR/issue-75930-derive-cfg.rs:49:13: 49:16 (#0), + span: $DIR/issue-75930-derive-cfg.rs:79:13: 79:16 (#0), }, Group { delimiter: Parenthesis, @@ -1725,64 +1725,64 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:52:17: 52:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:17: 82:18 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:52:19: 52:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:19: 82:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:52:23: 52:26 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:23: 82:26 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:52:27: 52:32 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:27: 82:32 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:26: 52:33 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:26: 82:33 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:22: 52:34 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:22: 82:34 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:52:18: 52:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:18: 82:35 (#0), }, Ident { ident: "i32", - span: $DIR/issue-75930-derive-cfg.rs:52:36: 52:39 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:36: 82:39 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:52:39: 52:40 (#0), + span: $DIR/issue-75930-derive-cfg.rs:82:39: 82:40 (#0), }, Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:53:39: 53:41 (#0), + span: $DIR/issue-75930-derive-cfg.rs:83:39: 83:41 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:49:16: 54:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:79:16: 84:14 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:48:24: 55:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:78:24: 85:10 (#0), }, Ident { ident: "struct", - span: $DIR/issue-75930-derive-cfg.rs:57:9: 57:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:9: 87:15 (#0), }, Ident { ident: "TupleStruct", - span: $DIR/issue-75930-derive-cfg.rs:57:16: 57:27 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:16: 87:27 (#0), }, Group { delimiter: Parenthesis, @@ -1790,115 +1790,115 @@ PRINT-DERIVE INPUT (DEBUG): TokenStream [ Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:59:13: 59:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:13: 89:14 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "cfg", - span: $DIR/issue-75930-derive-cfg.rs:59:15: 59:18 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:15: 89:18 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "not", - span: $DIR/issue-75930-derive-cfg.rs:59:19: 59:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:19: 89:22 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "FALSE", - span: $DIR/issue-75930-derive-cfg.rs:59:23: 59:28 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:23: 89:28 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:22: 59:29 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:22: 89:29 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:18: 59:30 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:18: 89:30 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:59:14: 59:31 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:14: 89:31 (#0), }, Ident { ident: "i32", - span: $DIR/issue-75930-derive-cfg.rs:59:32: 59:35 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:32: 89:35 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:59:35: 59:36 (#0), + span: $DIR/issue-75930-derive-cfg.rs:89:35: 89:36 (#0), }, Ident { ident: "u8", - span: $DIR/issue-75930-derive-cfg.rs:61:13: 61:15 (#0), + span: $DIR/issue-75930-derive-cfg.rs:91:13: 91:15 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:57:27: 62:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:87:27: 92:10 (#0), }, Punct { ch: ';', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:62:10: 62:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:92:10: 92:11 (#0), }, Literal { kind: Integer, symbol: "0", suffix: None, - span: $DIR/issue-75930-derive-cfg.rs:68:9: 68:10 (#0), + span: $DIR/issue-75930-derive-cfg.rs:98:9: 98:10 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:28:17: 69:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:17: 99:6 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:28:12: 69:7 (#0), + span: $DIR/issue-75930-derive-cfg.rs:58:12: 99:7 (#0), }, Punct { ch: ',', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:69:7: 69:8 (#0), + span: $DIR/issue-75930-derive-cfg.rs:99:7: 99:8 (#0), }, Punct { ch: '#', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:70:5: 70:6 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:5: 100:6 (#0), }, Group { delimiter: Bracket, stream: TokenStream [ Ident { ident: "print_helper", - span: $DIR/issue-75930-derive-cfg.rs:70:7: 70:19 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:7: 100:19 (#0), }, Group { delimiter: Parenthesis, stream: TokenStream [ Ident { ident: "d", - span: $DIR/issue-75930-derive-cfg.rs:70:20: 70:21 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:20: 100:21 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:70:19: 70:22 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:19: 100:22 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:70:6: 70:23 (#0), + span: $DIR/issue-75930-derive-cfg.rs:100:6: 100:23 (#0), }, Ident { ident: "fourth", - span: $DIR/issue-75930-derive-cfg.rs:71:5: 71:11 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:5: 101:11 (#0), }, Punct { ch: ':', spacing: Alone, - span: $DIR/issue-75930-derive-cfg.rs:71:11: 71:12 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:11: 101:12 (#0), }, Ident { ident: "B", - span: $DIR/issue-75930-derive-cfg.rs:71:13: 71:14 (#0), + span: $DIR/issue-75930-derive-cfg.rs:101:13: 101:14 (#0), }, ], - span: $DIR/issue-75930-derive-cfg.rs:25:32: 72:2 (#0), + span: $DIR/issue-75930-derive-cfg.rs:55:32: 102:2 (#0), }, ] From bb9c2f50c378d494e14f5d3062ed88ea90749637 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 8 Aug 2023 11:42:46 +1000 Subject: [PATCH 23/52] Reorder an expression to improve readability. --- compiler/rustc_parse/src/lexer/tokentrees.rs | 19 +++++++------------ 1 file changed, 7 insertions(+), 12 deletions(-) diff --git a/compiler/rustc_parse/src/lexer/tokentrees.rs b/compiler/rustc_parse/src/lexer/tokentrees.rs index 7cdb197047099..1d9dbfe4b89d0 100644 --- a/compiler/rustc_parse/src/lexer/tokentrees.rs +++ b/compiler/rustc_parse/src/lexer/tokentrees.rs @@ -55,19 +55,14 @@ impl<'a> TokenTreesReader<'a> { let (this_spacing, next_tok) = loop { let (next_tok, is_next_tok_preceded_by_whitespace) = self.string_reader.next_token(); - if !is_next_tok_preceded_by_whitespace { - if let Some(glued) = self.token.glue(&next_tok) { - self.token = glued; - } else { - let this_spacing = if next_tok.is_punct() { - Spacing::Joint - } else { - Spacing::Alone - }; - break (this_spacing, next_tok); - } - } else { + if is_next_tok_preceded_by_whitespace { break (Spacing::Alone, next_tok); + } else if let Some(glued) = self.token.glue(&next_tok) { + self.token = glued; + } else { + let this_spacing = + if next_tok.is_punct() { Spacing::Joint } else { Spacing::Alone }; + break (this_spacing, next_tok); } }; let this_tok = std::mem::replace(&mut self.token, next_tok); From 33aff5b1523b64052ae580f9bb6c7a7de94f16c5 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 11 Oct 2023 17:16:04 +1100 Subject: [PATCH 24/52] Use `TokenStream::token_alone` in one place. --- compiler/rustc_ast/src/attr/mod.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast/src/attr/mod.rs b/compiler/rustc_ast/src/attr/mod.rs index db008ea139d58..7b7078fabbb73 100644 --- a/compiler/rustc_ast/src/attr/mod.rs +++ b/compiler/rustc_ast/src/attr/mod.rs @@ -197,10 +197,10 @@ impl Attribute { .unwrap_or_else(|| panic!("attribute is missing tokens: {self:?}")) .to_attr_token_stream() .to_tokenstream(), - &AttrKind::DocComment(comment_kind, data) => TokenStream::new(vec![TokenTree::Token( - Token::new(token::DocComment(comment_kind, self.style, data), self.span), - Spacing::Alone, - )]), + &AttrKind::DocComment(comment_kind, data) => TokenStream::token_alone( + token::DocComment(comment_kind, self.style, data), + self.span, + ), } } } From 66c2b77a4a3d0b46c1abd2d90007b28e5de1b93d Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Thu, 12 Oct 2023 08:50:42 +1100 Subject: [PATCH 25/52] Rename `tt_prepend_space` as `space_between`. And reorder the arguments. I find it easier to think about this way. --- compiler/rustc_ast_pretty/src/pprust/state.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 8b7e91882fcc7..e71f421659e2e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -148,7 +148,7 @@ pub fn print_crate<'a>( /// This makes printed token streams look slightly nicer, /// and also addresses some specific regressions described in #63896 and #73345. -fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { +fn space_between(prev: &TokenTree, curr: &TokenTree) -> bool { if let TokenTree::Token(token, _) = prev { // No space after these tokens, e.g. `x.y`, `$e` // (The carets point to `prev`.) ^ ^ @@ -159,9 +159,9 @@ fn tt_prepend_space(tt: &TokenTree, prev: &TokenTree) -> bool { return comment_kind != CommentKind::Line; } } - match tt { + match curr { // No space before these tokens, e.g. `foo,`, `println!`, `x.y` - // (The carets point to `token`.) ^ ^ ^ + // (The carets point to `curr`.) ^ ^ ^ // // FIXME: having `Not` here works well for macro invocations like // `println!()`, but is bad when `!` means "logical not" or "the never @@ -575,7 +575,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere while let Some(tt) = iter.next() { self.print_tt(tt, convert_dollar_crate); if let Some(next) = iter.peek() { - if tt_prepend_space(next, tt) { + if space_between(tt, next) { self.space(); } } From a7ae2a6e6c68f0af5c3afcac015eea2bd18f6e27 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 12 Oct 2023 17:41:11 +1100 Subject: [PATCH 26/52] coverage: Simplify the detection of reloop edges to be given expressions --- .../src/coverage/counters.rs | 121 +++++++----------- .../rustc_mir_transform/src/coverage/graph.rs | 18 ++- 2 files changed, 57 insertions(+), 82 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 78845af016276..06770dafbaa06 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -510,18 +510,11 @@ impl<'a> MakeBcbCounters<'a> { traversal: &TraverseCoverageGraphWithLoops, branches: &[BcbBranch], ) -> BcbBranch { - let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch); - - let some_reloop_branch = self.find_some_reloop_branch(traversal, &branches); - if let Some(reloop_branch_without_counter) = - some_reloop_branch.filter(branch_needs_a_counter) - { - debug!( - "Selecting reloop_branch={:?} that still needs a counter, to get the \ - `Expression`", - reloop_branch_without_counter - ); - reloop_branch_without_counter + 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 } else { let &branch_without_counter = branches.iter().find(|&branch| self.branch_has_no_counter(branch)).expect( @@ -538,75 +531,52 @@ impl<'a> MakeBcbCounters<'a> { } } - /// At most, one of the branches (or its edge, from the branching_bcb, if the branch has - /// multiple incoming edges) can have a counter computed by expression. - /// - /// If at least one of the branches leads outside of a loop (`found_loop_exit` is - /// true), and at least one other branch does not exit the loop (the first of which - /// is captured in `some_reloop_branch`), it's likely any reloop branch will be - /// executed far more often than loop exit branch, making the reloop branch a better - /// candidate for an expression. - fn find_some_reloop_branch( + /// Tries to find a branch that leads back to the top of a loop, and that + /// doesn't already have a counter. Such branches are good candidates to + /// be given an expression (instead of a physical counter), because they + /// will tend to be executed more times than a loop-exit branch. + fn find_good_reloop_branch( &self, traversal: &TraverseCoverageGraphWithLoops, branches: &[BcbBranch], ) -> Option { - let branch_needs_a_counter = |branch: &BcbBranch| self.branch_has_no_counter(branch); - - let mut some_reloop_branch: Option = None; - for context in traversal.context_stack.iter().rev() { - if let Some((backedge_from_bcbs, _)) = &context.loop_backedges { - let mut found_loop_exit = false; - for &branch in branches.iter() { - if backedge_from_bcbs.iter().any(|&backedge_from_bcb| { - self.bcb_dominates(branch.target_bcb, backedge_from_bcb) - }) { - if let Some(reloop_branch) = some_reloop_branch { - if self.branch_has_no_counter(&reloop_branch) { - // we already found a candidate reloop_branch that still - // needs a counter - continue; - } - } - // The path from branch leads back to the top of the loop. Set this - // branch as the `reloop_branch`. If this branch already has a - // counter, and we find another reloop branch that doesn't have a - // counter yet, that branch will be selected as the `reloop_branch` - // instead. - some_reloop_branch = Some(branch); - } else { - // The path from branch leads outside this loop - found_loop_exit = true; - } - if found_loop_exit - && some_reloop_branch.filter(branch_needs_a_counter).is_some() - { - // Found both a branch that exits the loop and a branch that returns - // to the top of the loop (`reloop_branch`), and the `reloop_branch` - // doesn't already have a counter. - break; + // 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 { + // 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) + }); + + if is_reloop_branch { + all_branches_exit_this_loop = false; + if self.branch_has_no_counter(&branch) { + // We found a good branch to be given an expression. + return Some(branch); } + // Keep looking for another reloop branch without a counter. + } else { + // This branch exits the loop. } - if !found_loop_exit { - debug!( - "No branches exit the loop, so any branch without an existing \ - counter can have the `Expression`." - ); - break; - } - if some_reloop_branch.is_some() { - debug!( - "Found a branch that exits the loop and a branch the loops back to \ - the top of the loop (`reloop_branch`). The `reloop_branch` will \ - get the `Expression`, as long as it still needs a counter." - ); - break; - } - // else all branches exited this loop context, so run the same checks with - // the outer loop(s) } + + if !all_branches_exit_this_loop { + // We found one or more reloop branches, but all of them already + // have counters. Let the caller choose one of the exit branches. + debug!("All reloop branches had counters; skip checking the other loops"); + return None; + } + + // All of the branches exit this loop, so keep looking for a good + // reloop branch for one of the outer loops. } - some_reloop_branch + + None } #[inline] @@ -652,9 +622,4 @@ impl<'a> MakeBcbCounters<'a> { fn bcb_has_one_path_to_target(&self, bcb: BasicCoverageBlock) -> bool { self.bcb_predecessors(bcb).len() <= 1 } - - #[inline] - fn bcb_dominates(&self, dom: BasicCoverageBlock, node: BasicCoverageBlock) -> bool { - self.basic_coverage_blocks.dominates(dom, node) - } } diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 39027d21f066a..cf917ecee8664 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -386,17 +386,17 @@ fn bcb_filtered_successors<'a, 'tcx>( #[derive(Debug)] pub(super) struct TraversalContext { /// From one or more backedges returning to a loop header. - pub loop_backedges: Option<(Vec, BasicCoverageBlock)>, + loop_backedges: Option<(Vec, BasicCoverageBlock)>, /// worklist, to be traversed, of CoverageGraph in the loop with the given loop /// backedges, such that the loop is the inner inner-most loop containing these /// CoverageGraph - pub worklist: Vec, + worklist: Vec, } pub(super) struct TraverseCoverageGraphWithLoops { - pub backedges: IndexVec>, - pub context_stack: Vec, + backedges: IndexVec>, + context_stack: Vec, visited: BitSet, } @@ -414,6 +414,16 @@ impl TraverseCoverageGraphWithLoops { Self { backedges, context_stack, visited } } + /// For each loop on the loop context stack (top-down), yields a list of BCBs + /// within that loop that have an outgoing edge back to the loop header. + pub(super) fn reloop_bcbs_per_loop(&self) -> impl Iterator { + self.context_stack + .iter() + .rev() + .filter_map(|context| context.loop_backedges.as_ref()) + .map(|(from_bcbs, _to_bcb)| from_bcbs.as_slice()) + } + pub fn next(&mut self, basic_coverage_blocks: &CoverageGraph) -> Option { debug!( "TraverseCoverageGraphWithLoops::next - context_stack: {:?}", From d1920c518151b29e3326cdacc757a219817f3c73 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 12 Oct 2023 12:59:11 +1100 Subject: [PATCH 27/52] coverage: Rename `next_bcb` to just `bcb` This is the only BCB that `TraverseCoverageGraphWithLoops::next` works with, so calling it `next_bcb` just makes the code less clear. --- .../rustc_mir_transform/src/coverage/graph.rs | 19 ++++++++++--------- 1 file changed, 10 insertions(+), 9 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index cf917ecee8664..12fb897bd79c3 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -431,21 +431,22 @@ impl TraverseCoverageGraphWithLoops { ); while let Some(context) = self.context_stack.last_mut() { - if let Some(next_bcb) = context.worklist.pop() { - if !self.visited.insert(next_bcb) { - debug!("Already visited: {:?}", next_bcb); + if let Some(bcb) = context.worklist.pop() { + if !self.visited.insert(bcb) { + debug!("Already visited: {bcb:?}"); continue; } - debug!("Visiting {:?}", next_bcb); - if self.backedges[next_bcb].len() > 0 { - debug!("{:?} is a loop header! Start a new TraversalContext...", next_bcb); + debug!("Visiting {bcb:?}"); + + if self.backedges[bcb].len() > 0 { + debug!("{bcb:?} is a loop header! Start a new TraversalContext..."); self.context_stack.push(TraversalContext { - loop_backedges: Some((self.backedges[next_bcb].clone(), next_bcb)), + loop_backedges: Some((self.backedges[bcb].clone(), bcb)), worklist: Vec::new(), }); } - self.extend_worklist(basic_coverage_blocks, next_bcb); - return Some(next_bcb); + self.extend_worklist(basic_coverage_blocks, bcb); + return Some(bcb); } else { // Strip contexts with empty worklists from the top of the stack self.context_stack.pop(); From ea3fb7bc2cd64fc124209e6f4ffcda8d053fd7ae Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 12 Oct 2023 12:32:21 +1100 Subject: [PATCH 28/52] coverage: Use a `VecDeque` for loop traversal worklists The previous code was storing the worklist in a vector, and then selectively adding items to the start or end of the vector. That's a perfect use-case for a double-ended queue. This change also reveals that the existing code was a bit confused about which end of the worklist is the front or back. For now, items are always removed from the front of the queue (instead of the back), and code that adds items to the queue has been flipped, to preserve the existing behaviour. --- .../rustc_mir_transform/src/coverage/graph.rs | 49 +++++++------------ 1 file changed, 18 insertions(+), 31 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 12fb897bd79c3..8dc13117b9f4c 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -6,6 +6,7 @@ use rustc_index::{IndexSlice, IndexVec}; use rustc_middle::mir::{self, BasicBlock, TerminatorKind}; use std::cmp::Ordering; +use std::collections::VecDeque; use std::ops::{Index, IndexMut}; /// A coverage-specific simplification of the MIR control flow graph (CFG). The `CoverageGraph`s @@ -388,10 +389,8 @@ pub(super) struct TraversalContext { /// From one or more backedges returning to a loop header. loop_backedges: Option<(Vec, BasicCoverageBlock)>, - /// worklist, to be traversed, of CoverageGraph in the loop with the given loop - /// backedges, such that the loop is the inner inner-most loop containing these - /// CoverageGraph - worklist: Vec, + /// Worklist of BCBs to be processed in this context. + worklist: VecDeque, } pub(super) struct TraverseCoverageGraphWithLoops { @@ -402,10 +401,11 @@ pub(super) struct TraverseCoverageGraphWithLoops { impl TraverseCoverageGraphWithLoops { pub fn new(basic_coverage_blocks: &CoverageGraph) -> Self { - let start_bcb = basic_coverage_blocks.start_node(); let backedges = find_loop_backedges(basic_coverage_blocks); - let context_stack = - vec![TraversalContext { loop_backedges: None, worklist: vec![start_bcb] }]; + + let worklist = VecDeque::from([basic_coverage_blocks.start_node()]); + let context_stack = vec![TraversalContext { loop_backedges: None, worklist }]; + // `context_stack` starts with a `TraversalContext` for the main function context (beginning // with the `start` BasicCoverageBlock of the function). New worklists are pushed to the top // of the stack as loops are entered, and popped off of the stack when a loop's worklist is @@ -431,7 +431,7 @@ impl TraverseCoverageGraphWithLoops { ); while let Some(context) = self.context_stack.last_mut() { - if let Some(bcb) = context.worklist.pop() { + if let Some(bcb) = context.worklist.pop_front() { if !self.visited.insert(bcb) { debug!("Already visited: {bcb:?}"); continue; @@ -442,7 +442,7 @@ impl TraverseCoverageGraphWithLoops { debug!("{bcb:?} is a loop header! Start a new TraversalContext..."); self.context_stack.push(TraversalContext { loop_backedges: Some((self.backedges[bcb].clone(), bcb)), - worklist: Vec::new(), + worklist: VecDeque::new(), }); } self.extend_worklist(basic_coverage_blocks, bcb); @@ -484,7 +484,7 @@ impl TraverseCoverageGraphWithLoops { // blocks with only one successor, to prevent unnecessarily complicating // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the // branching block would have given an `Expression` (or vice versa). - let (some_successor_to_add, some_loop_header) = + let (some_successor_to_add, _) = if let Some((_, loop_header)) = context.loop_backedges { if basic_coverage_blocks.dominates(loop_header, successor) { (Some(successor), Some(loop_header)) @@ -494,30 +494,17 @@ impl TraverseCoverageGraphWithLoops { } else { (Some(successor), None) }; + + // FIXME: The code below had debug messages claiming to add items to a + // particular end of the worklist, but was confused about which end was + // which. The existing behaviour has been preserved for now, but it's + // unclear what the intended behaviour was. + if let Some(successor_to_add) = some_successor_to_add { if basic_coverage_blocks.successors[successor_to_add].len() > 1 { - debug!( - "{:?} successor is branching. Prioritize it at the beginning of \ - the {}", - successor_to_add, - if let Some(loop_header) = some_loop_header { - format!("worklist for the loop headed by {loop_header:?}") - } else { - String::from("non-loop worklist") - }, - ); - context.worklist.insert(0, successor_to_add); + context.worklist.push_back(successor_to_add); } else { - debug!( - "{:?} successor is non-branching. Defer it to the end of the {}", - successor_to_add, - if let Some(loop_header) = some_loop_header { - format!("worklist for the loop headed by {loop_header:?}") - } else { - String::from("non-loop worklist") - }, - ); - context.worklist.push(successor_to_add); + context.worklist.push_front(successor_to_add); } break; } From 15360b3bc8f75c33af8a41da5dc9a1cab19691ba Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 11 Oct 2023 17:40:37 +1100 Subject: [PATCH 29/52] coverage: Store a graph reference in the graph traversal struct Having to keep passing in a graph reference was a holdover from when the graph was partly mutated during traversal. As of #114354 that is no longer necessary, so we can simplify the traversal code by storing a graph reference as a field in `TraverseCoverageGraphWithLoops`. --- .../src/coverage/counters.rs | 10 ++++----- .../rustc_mir_transform/src/coverage/graph.rs | 21 +++++++++---------- .../rustc_mir_transform/src/coverage/tests.rs | 2 +- 3 files changed, 16 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/counters.rs b/compiler/rustc_mir_transform/src/coverage/counters.rs index 06770dafbaa06..77e3dee1fefa1 100644 --- a/compiler/rustc_mir_transform/src/coverage/counters.rs +++ b/compiler/rustc_mir_transform/src/coverage/counters.rs @@ -245,13 +245,13 @@ impl<'a> MakeBcbCounters<'a> { // the loop. The `traversal` state includes a `context_stack`, providing a way to know if // the current BCB is in one or more nested loops or not. let mut traversal = TraverseCoverageGraphWithLoops::new(&self.basic_coverage_blocks); - while let Some(bcb) = traversal.next(self.basic_coverage_blocks) { + 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)?; if self.bcb_needs_branch_counters(bcb) { - self.make_branch_counters(&mut traversal, bcb, branching_counter_operand)?; + self.make_branch_counters(&traversal, bcb, branching_counter_operand)?; } } else { debug!( @@ -274,7 +274,7 @@ impl<'a> MakeBcbCounters<'a> { fn make_branch_counters( &mut self, - traversal: &mut TraverseCoverageGraphWithLoops, + traversal: &TraverseCoverageGraphWithLoops<'_>, branching_bcb: BasicCoverageBlock, branching_counter_operand: Operand, ) -> Result<(), Error> { @@ -507,7 +507,7 @@ impl<'a> MakeBcbCounters<'a> { /// found, select any branch. fn choose_preferred_expression_branch( &self, - traversal: &TraverseCoverageGraphWithLoops, + traversal: &TraverseCoverageGraphWithLoops<'_>, branches: &[BcbBranch], ) -> BcbBranch { let good_reloop_branch = self.find_good_reloop_branch(traversal, &branches); @@ -537,7 +537,7 @@ impl<'a> MakeBcbCounters<'a> { /// will tend to be executed more times than a loop-exit branch. fn find_good_reloop_branch( &self, - traversal: &TraverseCoverageGraphWithLoops, + traversal: &TraverseCoverageGraphWithLoops<'_>, branches: &[BcbBranch], ) -> Option { // Consider each loop on the current traversal context stack, top-down. diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 8dc13117b9f4c..02bc62a7d2660 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -393,14 +393,16 @@ pub(super) struct TraversalContext { worklist: VecDeque, } -pub(super) struct TraverseCoverageGraphWithLoops { +pub(super) struct TraverseCoverageGraphWithLoops<'a> { + basic_coverage_blocks: &'a CoverageGraph, + backedges: IndexVec>, context_stack: Vec, visited: BitSet, } -impl TraverseCoverageGraphWithLoops { - pub fn new(basic_coverage_blocks: &CoverageGraph) -> Self { +impl<'a> TraverseCoverageGraphWithLoops<'a> { + pub(super) fn new(basic_coverage_blocks: &'a CoverageGraph) -> Self { let backedges = find_loop_backedges(basic_coverage_blocks); let worklist = VecDeque::from([basic_coverage_blocks.start_node()]); @@ -411,7 +413,7 @@ impl TraverseCoverageGraphWithLoops { // of the stack as loops are entered, and popped off of the stack when a loop's worklist is // exhausted. let visited = BitSet::new_empty(basic_coverage_blocks.num_nodes()); - Self { backedges, context_stack, visited } + Self { basic_coverage_blocks, backedges, context_stack, visited } } /// For each loop on the loop context stack (top-down), yields a list of BCBs @@ -424,7 +426,7 @@ impl TraverseCoverageGraphWithLoops { .map(|(from_bcbs, _to_bcb)| from_bcbs.as_slice()) } - pub fn next(&mut self, basic_coverage_blocks: &CoverageGraph) -> Option { + pub(super) fn next(&mut self) -> Option { debug!( "TraverseCoverageGraphWithLoops::next - context_stack: {:?}", self.context_stack.iter().rev().collect::>() @@ -445,7 +447,7 @@ impl TraverseCoverageGraphWithLoops { worklist: VecDeque::new(), }); } - self.extend_worklist(basic_coverage_blocks, bcb); + self.extend_worklist(bcb); return Some(bcb); } else { // Strip contexts with empty worklists from the top of the stack @@ -456,11 +458,8 @@ impl TraverseCoverageGraphWithLoops { None } - pub fn extend_worklist( - &mut self, - basic_coverage_blocks: &CoverageGraph, - bcb: BasicCoverageBlock, - ) { + pub fn extend_worklist(&mut self, bcb: BasicCoverageBlock) { + let Self { basic_coverage_blocks, .. } = *self; let successors = &basic_coverage_blocks.successors[bcb]; debug!("{:?} has {} successors:", bcb, successors.len()); for &successor in successors { diff --git a/compiler/rustc_mir_transform/src/coverage/tests.rs b/compiler/rustc_mir_transform/src/coverage/tests.rs index ee7cb791c8180..487d22823644b 100644 --- a/compiler/rustc_mir_transform/src/coverage/tests.rs +++ b/compiler/rustc_mir_transform/src/coverage/tests.rs @@ -628,7 +628,7 @@ fn test_traverse_coverage_with_loops() { let basic_coverage_blocks = graph::CoverageGraph::from_mir(&mir_body); let mut traversed_in_order = Vec::new(); let mut traversal = graph::TraverseCoverageGraphWithLoops::new(&basic_coverage_blocks); - while let Some(bcb) = traversal.next(&basic_coverage_blocks) { + while let Some(bcb) = traversal.next() { traversed_in_order.push(bcb); } From 59f4f1c89d035bffbb6455f1dc25a45f09c837a5 Mon Sep 17 00:00:00 2001 From: Zalathar Date: Wed, 11 Oct 2023 20:33:26 +1100 Subject: [PATCH 30/52] coverage: Don't store loop backedges in the traversal context As long as we store the loop header BCB, we can look up its incoming loop backedges as needed. --- .../rustc_mir_transform/src/coverage/graph.rs | 17 ++++++++++------- 1 file changed, 10 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 02bc62a7d2660..2a88a5f7f44e2 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -386,8 +386,11 @@ fn bcb_filtered_successors<'a, 'tcx>( /// ensures a loop is completely traversed before processing Blocks after the end of the loop. #[derive(Debug)] pub(super) struct TraversalContext { - /// From one or more backedges returning to a loop header. - loop_backedges: Option<(Vec, BasicCoverageBlock)>, + /// BCB with one or more incoming loop backedges, indicating which loop + /// this context is for. + /// + /// If `None`, this is the non-loop context for the function as a whole. + loop_header: Option, /// Worklist of BCBs to be processed in this context. worklist: VecDeque, @@ -406,7 +409,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { let backedges = find_loop_backedges(basic_coverage_blocks); let worklist = VecDeque::from([basic_coverage_blocks.start_node()]); - let context_stack = vec![TraversalContext { loop_backedges: None, worklist }]; + let context_stack = vec![TraversalContext { loop_header: None, worklist }]; // `context_stack` starts with a `TraversalContext` for the main function context (beginning // with the `start` BasicCoverageBlock of the function). New worklists are pushed to the top @@ -422,8 +425,8 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { self.context_stack .iter() .rev() - .filter_map(|context| context.loop_backedges.as_ref()) - .map(|(from_bcbs, _to_bcb)| from_bcbs.as_slice()) + .filter_map(|context| context.loop_header) + .map(|header_bcb| self.backedges[header_bcb].as_slice()) } pub(super) fn next(&mut self) -> Option { @@ -443,7 +446,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { if self.backedges[bcb].len() > 0 { debug!("{bcb:?} is a loop header! Start a new TraversalContext..."); self.context_stack.push(TraversalContext { - loop_backedges: Some((self.backedges[bcb].clone(), bcb)), + loop_header: Some(bcb), worklist: VecDeque::new(), }); } @@ -484,7 +487,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the // branching block would have given an `Expression` (or vice versa). let (some_successor_to_add, _) = - if let Some((_, loop_header)) = context.loop_backedges { + if let Some(loop_header) = context.loop_header { if basic_coverage_blocks.dominates(loop_header, successor) { (Some(successor), Some(loop_header)) } else { From d99ab97b027917b434790b76492386310b47978d Mon Sep 17 00:00:00 2001 From: Zalathar Date: Thu, 12 Oct 2023 13:31:35 +1100 Subject: [PATCH 31/52] coverage: Simplify adding BCB successors to the traversal worklists --- .../rustc_mir_transform/src/coverage/graph.rs | 77 ++++++++++--------- 1 file changed, 39 insertions(+), 38 deletions(-) diff --git a/compiler/rustc_mir_transform/src/coverage/graph.rs b/compiler/rustc_mir_transform/src/coverage/graph.rs index 2a88a5f7f44e2..9a7adaada09fc 100644 --- a/compiler/rustc_mir_transform/src/coverage/graph.rs +++ b/compiler/rustc_mir_transform/src/coverage/graph.rs @@ -450,7 +450,7 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { worklist: VecDeque::new(), }); } - self.extend_worklist(bcb); + self.add_successors_to_worklists(bcb); return Some(bcb); } else { // Strip contexts with empty worklists from the top of the stack @@ -461,10 +461,10 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { None } - pub fn extend_worklist(&mut self, bcb: BasicCoverageBlock) { - let Self { basic_coverage_blocks, .. } = *self; - let successors = &basic_coverage_blocks.successors[bcb]; + pub fn add_successors_to_worklists(&mut self, bcb: BasicCoverageBlock) { + let successors = &self.basic_coverage_blocks.successors[bcb]; debug!("{:?} has {} successors:", bcb, successors.len()); + for &successor in successors { if successor == bcb { debug!( @@ -473,43 +473,44 @@ impl<'a> TraverseCoverageGraphWithLoops<'a> { bcb ); // Don't re-add this successor to the worklist. We are already processing it. + // FIXME: This claims to skip just the self-successor, but it actually skips + // all other successors as well. Does that matter? break; } - for context in self.context_stack.iter_mut().rev() { - // Add successors of the current BCB to the appropriate context. Successors that - // stay within a loop are added to the BCBs context worklist. Successors that - // exit the loop (they are not dominated by the loop header) must be reachable - // from other BCBs outside the loop, and they will be added to a different - // worklist. - // - // Branching blocks (with more than one successor) must be processed before - // blocks with only one successor, to prevent unnecessarily complicating - // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the - // branching block would have given an `Expression` (or vice versa). - let (some_successor_to_add, _) = - if let Some(loop_header) = context.loop_header { - if basic_coverage_blocks.dominates(loop_header, successor) { - (Some(successor), Some(loop_header)) - } else { - (None, None) - } - } else { - (Some(successor), None) - }; - - // FIXME: The code below had debug messages claiming to add items to a - // particular end of the worklist, but was confused about which end was - // which. The existing behaviour has been preserved for now, but it's - // unclear what the intended behaviour was. - - if let Some(successor_to_add) = some_successor_to_add { - if basic_coverage_blocks.successors[successor_to_add].len() > 1 { - context.worklist.push_back(successor_to_add); - } else { - context.worklist.push_front(successor_to_add); + + // Add successors of the current BCB to the appropriate context. Successors that + // stay within a loop are added to the BCBs context worklist. Successors that + // exit the loop (they are not dominated by the loop header) must be reachable + // from other BCBs outside the loop, and they will be added to a different + // worklist. + // + // Branching blocks (with more than one successor) must be processed before + // blocks with only one successor, to prevent unnecessarily complicating + // `Expression`s by creating a Counter in a `BasicCoverageBlock` that the + // branching block would have given an `Expression` (or vice versa). + + let context = self + .context_stack + .iter_mut() + .rev() + .find(|context| match context.loop_header { + Some(loop_header) => { + self.basic_coverage_blocks.dominates(loop_header, successor) } - break; - } + None => true, + }) + .unwrap_or_else(|| bug!("should always fall back to the root non-loop context")); + debug!("adding to worklist for {:?}", context.loop_header); + + // FIXME: The code below had debug messages claiming to add items to a + // particular end of the worklist, but was confused about which end was + // which. The existing behaviour has been preserved for now, but it's + // unclear what the intended behaviour was. + + if self.basic_coverage_blocks.successors[successor].len() > 1 { + context.worklist.push_back(successor); + } else { + context.worklist.push_front(successor); } } } From 8309097163103910a08c0ed79def88ae178699ac Mon Sep 17 00:00:00 2001 From: Eric Huss Date: Thu, 12 Oct 2023 08:45:02 -0700 Subject: [PATCH 32/52] Fix mips platform support entries. --- src/doc/rustc/src/platform-support.md | 4 ---- 1 file changed, 4 deletions(-) diff --git a/src/doc/rustc/src/platform-support.md b/src/doc/rustc/src/platform-support.md index d25fa661c3f3a..1fb5e56db5d76 100644 --- a/src/doc/rustc/src/platform-support.md +++ b/src/doc/rustc/src/platform-support.md @@ -286,10 +286,6 @@ target | std | host | notes `mipsel-unknown-linux-musl` | ✓ | | MIPS (little endian) Linux with musl libc `mipsel-sony-psp` | * | | MIPS (LE) Sony PlayStation Portable (PSP) [`mipsel-sony-psx`](platform-support/mipsel-sony-psx.md) | * | | MIPS (LE) Sony PlayStation 1 (PSX) -`mips-unknown-linux-gnu` | MIPS Linux (kernel 4.4, glibc 2.23) -`mips64-unknown-linux-gnuabi64` | MIPS64 Linux, n64 ABI (kernel 4.4, glibc 2.23) -`mips64el-unknown-linux-gnuabi64` | MIPS64 (LE) Linux, n64 ABI (kernel 4.4, glibc 2.23) -`mipsel-unknown-linux-gnu` | MIPS (LE) Linux (kernel 4.4, glibc 2.23) `mipsel-unknown-linux-uclibc` | ✓ | | MIPS (LE) Linux with uClibc `mipsel-unknown-none` | * | | Bare MIPS (LE) softfloat [`mipsisa32r6-unknown-linux-gnu`](platform-support/mips-release-6.md) | ? | | 32-bit MIPS Release 6 Big Endian From 72815dc08fd676ec22463055d71855523cf67e44 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 12 Oct 2023 16:46:27 +0200 Subject: [PATCH 33/52] check-cfg: adjust expected names and values when useful --- compiler/rustc_lint/src/context.rs | 13 ++++++++++- tests/ui/check-cfg/allow-same-level.stderr | 1 + tests/ui/check-cfg/compact-names.stderr | 1 + tests/ui/check-cfg/diagnotics.stderr | 1 - tests/ui/check-cfg/empty-names.stderr | 1 + tests/ui/check-cfg/mix.stderr | 26 ++++++++++++++++++++++ tests/ui/check-cfg/stmt-no-ice.stderr | 1 + 7 files changed, 42 insertions(+), 2 deletions(-) diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 3c5cde4309b44..93d155505c417 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -727,11 +727,14 @@ pub trait LintContext: Sized { .collect::>(); possibilities.sort(); + let mut should_print_possibilities = true; if let Some((value, value_span)) = value { if best_match_values.contains(&Some(value)) { db.span_suggestion(name_span, "there is a config with a similar name and value", best_match, Applicability::MaybeIncorrect); + should_print_possibilities = false; } else if best_match_values.contains(&None) { db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and no value", best_match, Applicability::MaybeIncorrect); + should_print_possibilities = false; } else if let Some(first_value) = possibilities.first() { db.span_suggestion(name_span.to(value_span), "there is a config with a similar name and different values", format!("{best_match} = \"{first_value}\""), Applicability::MaybeIncorrect); } else { @@ -741,13 +744,21 @@ pub trait LintContext: Sized { db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect); } - if !possibilities.is_empty() { + if !possibilities.is_empty() && should_print_possibilities { let possibilities = possibilities.join("`, `"); db.help(format!("expected values for `{best_match}` are: `{possibilities}`")); } } else { db.span_suggestion(name_span, "there is a config with a similar name", best_match, Applicability::MaybeIncorrect); } + } else if !possibilities.is_empty() { + let mut possibilities = possibilities.iter() + .map(Symbol::as_str) + .collect::>(); + possibilities.sort(); + let possibilities = possibilities.join("`, `"); + + db.help(format!("expected names are: `{possibilities}`")); } }, BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => { diff --git a/tests/ui/check-cfg/allow-same-level.stderr b/tests/ui/check-cfg/allow-same-level.stderr index 7797de584b9e1..b46720f62c426 100644 --- a/tests/ui/check-cfg/allow-same-level.stderr +++ b/tests/ui/check-cfg/allow-same-level.stderr @@ -4,6 +4,7 @@ warning: unexpected `cfg` condition name LL | #[cfg(FALSE)] | ^^^^^ | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` = note: `#[warn(unexpected_cfgs)]` on by default warning: 1 warning emitted diff --git a/tests/ui/check-cfg/compact-names.stderr b/tests/ui/check-cfg/compact-names.stderr index f1fc4285a71b7..4a05c783bff38 100644 --- a/tests/ui/check-cfg/compact-names.stderr +++ b/tests/ui/check-cfg/compact-names.stderr @@ -4,6 +4,7 @@ warning: unexpected `cfg` condition name LL | #[cfg(target(os = "linux", architecture = "arm"))] | ^^^^^^^^^^^^^^^^^^^^ | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` = note: `#[warn(unexpected_cfgs)]` on by default warning: 1 warning emitted diff --git a/tests/ui/check-cfg/diagnotics.stderr b/tests/ui/check-cfg/diagnotics.stderr index 8b9fef09d09ec..39ceb24ee65da 100644 --- a/tests/ui/check-cfg/diagnotics.stderr +++ b/tests/ui/check-cfg/diagnotics.stderr @@ -13,7 +13,6 @@ warning: unexpected `cfg` condition name LL | #[cfg(featur = "foo")] | ^^^^^^^^^^^^^^ | - = help: expected values for `feature` are: `foo` help: there is a config with a similar name and value | LL | #[cfg(feature = "foo")] diff --git a/tests/ui/check-cfg/empty-names.stderr b/tests/ui/check-cfg/empty-names.stderr index f926d1133cced..4443f5dd55bdb 100644 --- a/tests/ui/check-cfg/empty-names.stderr +++ b/tests/ui/check-cfg/empty-names.stderr @@ -4,6 +4,7 @@ warning: unexpected `cfg` condition name LL | #[cfg(unknown_key = "value")] | ^^^^^^^^^^^^^^^^^^^^^ | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` = note: `#[warn(unexpected_cfgs)]` on by default warning: 1 warning emitted diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index 07c514aed5242..d2dedece20e55 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -35,6 +35,8 @@ warning: unexpected `cfg` condition name | LL | #[cfg_attr(uu, test)] | ^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected condition value `bar` for condition name `feature` | @@ -71,18 +73,24 @@ warning: unexpected `cfg` condition name | LL | cfg!(xxx = "foo"); | ^^^^^^^^^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name --> $DIR/mix.rs:48:10 | LL | cfg!(xxx); | ^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name --> $DIR/mix.rs:50:14 | LL | cfg!(any(xxx, windows)); | ^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition value --> $DIR/mix.rs:52:14 @@ -97,36 +105,48 @@ warning: unexpected `cfg` condition name | LL | cfg!(any(windows, xxx)); | ^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name --> $DIR/mix.rs:56:20 | LL | cfg!(all(unix, xxx)); | ^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name --> $DIR/mix.rs:58:14 | LL | cfg!(all(aa, bb)); | ^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name --> $DIR/mix.rs:58:18 | LL | cfg!(all(aa, bb)); | ^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name --> $DIR/mix.rs:61:14 | LL | cfg!(any(aa, bb)); | ^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name --> $DIR/mix.rs:61:18 | LL | cfg!(any(aa, bb)); | ^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition value --> $DIR/mix.rs:64:20 @@ -141,6 +161,8 @@ warning: unexpected `cfg` condition name | LL | cfg!(any(xxx, feature = "zebra")); | ^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition value --> $DIR/mix.rs:66:19 @@ -155,12 +177,16 @@ warning: unexpected `cfg` condition name | LL | cfg!(any(xxx, unix, xxx)); | ^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name --> $DIR/mix.rs:69:25 | LL | cfg!(any(xxx, unix, xxx)); | ^^^ + | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition value --> $DIR/mix.rs:72:14 diff --git a/tests/ui/check-cfg/stmt-no-ice.stderr b/tests/ui/check-cfg/stmt-no-ice.stderr index da65b596911d2..cf8ff5802923d 100644 --- a/tests/ui/check-cfg/stmt-no-ice.stderr +++ b/tests/ui/check-cfg/stmt-no-ice.stderr @@ -4,6 +4,7 @@ warning: unexpected `cfg` condition name LL | #[cfg(crossbeam_loom)] | ^^^^^^^^^^^^^^ | + = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` = note: `#[warn(unexpected_cfgs)]` on by default warning: 1 warning emitted From dcfc484b094f28ed6579ad10dbdc2d18ddf59e4f Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 12 Oct 2023 16:49:56 +0200 Subject: [PATCH 34/52] check-cfg: mention the unexpected name and value in the primary message --- compiler/rustc_attr/src/builtin.rs | 8 ++- tests/ui/check-cfg/allow-same-level.stderr | 2 +- tests/ui/check-cfg/compact-names.stderr | 2 +- tests/ui/check-cfg/compact-values.stderr | 2 +- tests/ui/check-cfg/diagnotics.stderr | 12 ++--- tests/ui/check-cfg/empty-names.stderr | 2 +- tests/ui/check-cfg/empty-values.stderr | 2 +- tests/ui/check-cfg/invalid-cfg-name.stderr | 2 +- tests/ui/check-cfg/invalid-cfg-value.stderr | 4 +- tests/ui/check-cfg/mix.stderr | 52 +++++++++---------- tests/ui/check-cfg/no-values.stderr | 4 +- .../order-independant.names_after.stderr | 4 +- .../order-independant.names_before.stderr | 4 +- tests/ui/check-cfg/stmt-no-ice.stderr | 2 +- tests/ui/check-cfg/values-target-json.stderr | 2 +- tests/ui/check-cfg/well-known-names.stderr | 6 +-- tests/ui/check-cfg/well-known-values.stderr | 10 ++-- 17 files changed, 62 insertions(+), 58 deletions(-) diff --git a/compiler/rustc_attr/src/builtin.rs b/compiler/rustc_attr/src/builtin.rs index f013ff45a4fe5..76659458dad99 100644 --- a/compiler/rustc_attr/src/builtin.rs +++ b/compiler/rustc_attr/src/builtin.rs @@ -548,7 +548,11 @@ pub fn cfg_matches( UNEXPECTED_CFGS, cfg.span, lint_node_id, - "unexpected `cfg` condition value", + if let Some(value) = cfg.value { + format!("unexpected `cfg` condition value: `{value}`") + } else { + format!("unexpected `cfg` condition value: (none)") + }, BuiltinLintDiagnostics::UnexpectedCfgValue( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), @@ -560,7 +564,7 @@ pub fn cfg_matches( UNEXPECTED_CFGS, cfg.span, lint_node_id, - "unexpected `cfg` condition name", + format!("unexpected `cfg` condition name: `{}`", cfg.name), BuiltinLintDiagnostics::UnexpectedCfgName( (cfg.name, cfg.name_span), cfg.value.map(|v| (v, cfg.value_span.unwrap())), diff --git a/tests/ui/check-cfg/allow-same-level.stderr b/tests/ui/check-cfg/allow-same-level.stderr index b46720f62c426..b0c459fabf8eb 100644 --- a/tests/ui/check-cfg/allow-same-level.stderr +++ b/tests/ui/check-cfg/allow-same-level.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `FALSE` --> $DIR/allow-same-level.rs:7:7 | LL | #[cfg(FALSE)] diff --git a/tests/ui/check-cfg/compact-names.stderr b/tests/ui/check-cfg/compact-names.stderr index 4a05c783bff38..b0228774b751b 100644 --- a/tests/ui/check-cfg/compact-names.stderr +++ b/tests/ui/check-cfg/compact-names.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `target_architecture` --> $DIR/compact-names.rs:11:28 | LL | #[cfg(target(os = "linux", architecture = "arm"))] diff --git a/tests/ui/check-cfg/compact-values.stderr b/tests/ui/check-cfg/compact-values.stderr index b7269a652eaa7..bb2f4915b5ef6 100644 --- a/tests/ui/check-cfg/compact-values.stderr +++ b/tests/ui/check-cfg/compact-values.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `X` --> $DIR/compact-values.rs:11:28 | LL | #[cfg(target(os = "linux", arch = "X"))] diff --git a/tests/ui/check-cfg/diagnotics.stderr b/tests/ui/check-cfg/diagnotics.stderr index 39ceb24ee65da..31c0db03a7e0f 100644 --- a/tests/ui/check-cfg/diagnotics.stderr +++ b/tests/ui/check-cfg/diagnotics.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `featur` --> $DIR/diagnotics.rs:4:7 | LL | #[cfg(featur)] @@ -7,7 +7,7 @@ LL | #[cfg(featur)] = help: expected values for `feature` are: `foo` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `featur` --> $DIR/diagnotics.rs:8:7 | LL | #[cfg(featur = "foo")] @@ -18,7 +18,7 @@ help: there is a config with a similar name and value LL | #[cfg(feature = "foo")] | ~~~~~~~ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `featur` --> $DIR/diagnotics.rs:12:7 | LL | #[cfg(featur = "fo")] @@ -30,13 +30,13 @@ help: there is a config with a similar name and different values LL | #[cfg(feature = "foo")] | ~~~~~~~~~~~~~~~ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `no_value` --> $DIR/diagnotics.rs:19:7 | LL | #[cfg(no_value)] | ^^^^^^^^ help: there is a config with a similar name: `no_values` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `no_value` --> $DIR/diagnotics.rs:23:7 | LL | #[cfg(no_value = "foo")] @@ -47,7 +47,7 @@ help: there is a config with a similar name and no value LL | #[cfg(no_values)] | ~~~~~~~~~ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `bar` --> $DIR/diagnotics.rs:27:7 | LL | #[cfg(no_values = "bar")] diff --git a/tests/ui/check-cfg/empty-names.stderr b/tests/ui/check-cfg/empty-names.stderr index 4443f5dd55bdb..9bba852c6defd 100644 --- a/tests/ui/check-cfg/empty-names.stderr +++ b/tests/ui/check-cfg/empty-names.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `unknown_key` --> $DIR/empty-names.rs:6:7 | LL | #[cfg(unknown_key = "value")] diff --git a/tests/ui/check-cfg/empty-values.stderr b/tests/ui/check-cfg/empty-values.stderr index a0168b2caa8e3..932651c5bfe17 100644 --- a/tests/ui/check-cfg/empty-values.stderr +++ b/tests/ui/check-cfg/empty-values.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `value` --> $DIR/empty-values.rs:6:7 | LL | #[cfg(test = "value")] diff --git a/tests/ui/check-cfg/invalid-cfg-name.stderr b/tests/ui/check-cfg/invalid-cfg-name.stderr index ed09f8cb66d29..8c3c72c96671f 100644 --- a/tests/ui/check-cfg/invalid-cfg-name.stderr +++ b/tests/ui/check-cfg/invalid-cfg-name.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `widnows` --> $DIR/invalid-cfg-name.rs:7:7 | LL | #[cfg(widnows)] diff --git a/tests/ui/check-cfg/invalid-cfg-value.stderr b/tests/ui/check-cfg/invalid-cfg-value.stderr index 776d264a7adcb..947beac6ffd6e 100644 --- a/tests/ui/check-cfg/invalid-cfg-value.stderr +++ b/tests/ui/check-cfg/invalid-cfg-value.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `sedre` --> $DIR/invalid-cfg-value.rs:7:7 | LL | #[cfg(feature = "sedre")] @@ -9,7 +9,7 @@ LL | #[cfg(feature = "sedre")] = note: expected values for `feature` are: `full`, `serde` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `rand` --> $DIR/invalid-cfg-value.rs:14:7 | LL | #[cfg(feature = "rand")] diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index d2dedece20e55..b862239bfdcd7 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `widnows` --> $DIR/mix.rs:11:7 | LL | #[cfg(widnows)] @@ -6,7 +6,7 @@ LL | #[cfg(widnows)] | = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: (none) --> $DIR/mix.rs:15:7 | LL | #[cfg(feature)] @@ -14,7 +14,7 @@ LL | #[cfg(feature)] | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `bar` --> $DIR/mix.rs:22:7 | LL | #[cfg(feature = "bar")] @@ -22,7 +22,7 @@ LL | #[cfg(feature = "bar")] | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `zebra` --> $DIR/mix.rs:26:7 | LL | #[cfg(feature = "zebra")] @@ -30,7 +30,7 @@ LL | #[cfg(feature = "zebra")] | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `uu` --> $DIR/mix.rs:30:12 | LL | #[cfg_attr(uu, test)] @@ -46,13 +46,13 @@ warning: unexpected `unknown_name` as condition name | = help: was set with `--cfg` but isn't in the `--check-cfg` expected names -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `widnows` --> $DIR/mix.rs:39:10 | LL | cfg!(widnows); | ^^^^^^^ help: there is a config with a similar name: `windows` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `bar` --> $DIR/mix.rs:42:10 | LL | cfg!(feature = "bar"); @@ -60,7 +60,7 @@ LL | cfg!(feature = "bar"); | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `zebra` --> $DIR/mix.rs:44:10 | LL | cfg!(feature = "zebra"); @@ -68,7 +68,7 @@ LL | cfg!(feature = "zebra"); | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:46:10 | LL | cfg!(xxx = "foo"); @@ -76,7 +76,7 @@ LL | cfg!(xxx = "foo"); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:48:10 | LL | cfg!(xxx); @@ -84,7 +84,7 @@ LL | cfg!(xxx); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:50:14 | LL | cfg!(any(xxx, windows)); @@ -92,7 +92,7 @@ LL | cfg!(any(xxx, windows)); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `bad` --> $DIR/mix.rs:52:14 | LL | cfg!(any(feature = "bad", windows)); @@ -100,7 +100,7 @@ LL | cfg!(any(feature = "bad", windows)); | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:54:23 | LL | cfg!(any(windows, xxx)); @@ -108,7 +108,7 @@ LL | cfg!(any(windows, xxx)); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:56:20 | LL | cfg!(all(unix, xxx)); @@ -116,7 +116,7 @@ LL | cfg!(all(unix, xxx)); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `aa` --> $DIR/mix.rs:58:14 | LL | cfg!(all(aa, bb)); @@ -124,7 +124,7 @@ LL | cfg!(all(aa, bb)); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `bb` --> $DIR/mix.rs:58:18 | LL | cfg!(all(aa, bb)); @@ -132,7 +132,7 @@ LL | cfg!(all(aa, bb)); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `aa` --> $DIR/mix.rs:61:14 | LL | cfg!(any(aa, bb)); @@ -140,7 +140,7 @@ LL | cfg!(any(aa, bb)); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `bb` --> $DIR/mix.rs:61:18 | LL | cfg!(any(aa, bb)); @@ -148,7 +148,7 @@ LL | cfg!(any(aa, bb)); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `zebra` --> $DIR/mix.rs:64:20 | LL | cfg!(any(unix, feature = "zebra")); @@ -156,7 +156,7 @@ LL | cfg!(any(unix, feature = "zebra")); | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:66:14 | LL | cfg!(any(xxx, feature = "zebra")); @@ -164,7 +164,7 @@ LL | cfg!(any(xxx, feature = "zebra")); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `zebra` --> $DIR/mix.rs:66:19 | LL | cfg!(any(xxx, feature = "zebra")); @@ -172,7 +172,7 @@ LL | cfg!(any(xxx, feature = "zebra")); | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:69:14 | LL | cfg!(any(xxx, unix, xxx)); @@ -180,7 +180,7 @@ LL | cfg!(any(xxx, unix, xxx)); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:69:25 | LL | cfg!(any(xxx, unix, xxx)); @@ -188,7 +188,7 @@ LL | cfg!(any(xxx, unix, xxx)); | = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `zebra` --> $DIR/mix.rs:72:14 | LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); @@ -196,7 +196,7 @@ LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `zebra` --> $DIR/mix.rs:72:33 | LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); @@ -204,7 +204,7 @@ LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); | = note: expected values for `feature` are: `foo` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `zebra` --> $DIR/mix.rs:72:52 | LL | cfg!(all(feature = "zebra", feature = "zebra", feature = "zebra")); diff --git a/tests/ui/check-cfg/no-values.stderr b/tests/ui/check-cfg/no-values.stderr index ffa87dc58f203..b05a569dd01cd 100644 --- a/tests/ui/check-cfg/no-values.stderr +++ b/tests/ui/check-cfg/no-values.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `foo` --> $DIR/no-values.rs:6:7 | LL | #[cfg(feature = "foo")] @@ -9,7 +9,7 @@ LL | #[cfg(feature = "foo")] = note: no expected value for `feature` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `foo` --> $DIR/no-values.rs:10:7 | LL | #[cfg(test = "foo")] diff --git a/tests/ui/check-cfg/order-independant.names_after.stderr b/tests/ui/check-cfg/order-independant.names_after.stderr index 91b81428b38a4..a308358e48587 100644 --- a/tests/ui/check-cfg/order-independant.names_after.stderr +++ b/tests/ui/check-cfg/order-independant.names_after.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: (none) --> $DIR/order-independant.rs:8:7 | LL | #[cfg(a)] @@ -7,7 +7,7 @@ LL | #[cfg(a)] = note: expected values for `a` are: `b` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `unk` --> $DIR/order-independant.rs:12:7 | LL | #[cfg(a = "unk")] diff --git a/tests/ui/check-cfg/order-independant.names_before.stderr b/tests/ui/check-cfg/order-independant.names_before.stderr index 91b81428b38a4..a308358e48587 100644 --- a/tests/ui/check-cfg/order-independant.names_before.stderr +++ b/tests/ui/check-cfg/order-independant.names_before.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: (none) --> $DIR/order-independant.rs:8:7 | LL | #[cfg(a)] @@ -7,7 +7,7 @@ LL | #[cfg(a)] = note: expected values for `a` are: `b` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `unk` --> $DIR/order-independant.rs:12:7 | LL | #[cfg(a = "unk")] diff --git a/tests/ui/check-cfg/stmt-no-ice.stderr b/tests/ui/check-cfg/stmt-no-ice.stderr index cf8ff5802923d..900ea4e4da06c 100644 --- a/tests/ui/check-cfg/stmt-no-ice.stderr +++ b/tests/ui/check-cfg/stmt-no-ice.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `crossbeam_loom` --> $DIR/stmt-no-ice.rs:7:11 | LL | #[cfg(crossbeam_loom)] diff --git a/tests/ui/check-cfg/values-target-json.stderr b/tests/ui/check-cfg/values-target-json.stderr index c705152d9fc66..e71149f337f58 100644 --- a/tests/ui/check-cfg/values-target-json.stderr +++ b/tests/ui/check-cfg/values-target-json.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `linuz` --> $DIR/values-target-json.rs:13:7 | LL | #[cfg(target_os = "linuz")] diff --git a/tests/ui/check-cfg/well-known-names.stderr b/tests/ui/check-cfg/well-known-names.stderr index 34c5d6172d94d..a5d38a99eeec9 100644 --- a/tests/ui/check-cfg/well-known-names.stderr +++ b/tests/ui/check-cfg/well-known-names.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `target_oz` --> $DIR/well-known-names.rs:6:7 | LL | #[cfg(target_oz = "linux")] @@ -8,7 +8,7 @@ LL | #[cfg(target_oz = "linux")] | = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `features` --> $DIR/well-known-names.rs:13:7 | LL | #[cfg(features = "foo")] @@ -16,7 +16,7 @@ LL | #[cfg(features = "foo")] | | | help: there is a config with a similar name: `feature` -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `uniw` --> $DIR/well-known-names.rs:20:7 | LL | #[cfg(uniw)] diff --git a/tests/ui/check-cfg/well-known-values.stderr b/tests/ui/check-cfg/well-known-values.stderr index b381f5a4a0a15..6877d8f5bb727 100644 --- a/tests/ui/check-cfg/well-known-values.stderr +++ b/tests/ui/check-cfg/well-known-values.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `linuz` --> $DIR/well-known-values.rs:7:7 | LL | #[cfg(target_os = "linuz")] @@ -9,7 +9,7 @@ LL | #[cfg(target_os = "linuz")] = note: expected values for `target_os` are: `aix`, `android`, `cuda`, `dragonfly`, `emscripten`, `espidf`, `freebsd`, `fuchsia`, `haiku`, `hermit`, `horizon`, `hurd`, `illumos`, `ios`, `l4re`, `linux`, `macos`, `netbsd`, `none`, `nto`, `openbsd`, `psp`, `redox`, `solaris`, `solid_asp3`, `teeos`, `tvos`, `uefi`, `unknown`, `vita`, `vxworks`, `wasi`, `watchos`, `windows`, `xous` = note: `#[warn(unexpected_cfgs)]` on by default -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `0` --> $DIR/well-known-values.rs:14:7 | LL | #[cfg(target_has_atomic = "0")] @@ -19,7 +19,7 @@ LL | #[cfg(target_has_atomic = "0")] | = note: expected values for `target_has_atomic` are: (none), `128`, `16`, `32`, `64`, `8`, `ptr` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `aa` --> $DIR/well-known-values.rs:21:7 | LL | #[cfg(unix = "aa")] @@ -29,7 +29,7 @@ LL | #[cfg(unix = "aa")] | = note: no expected value for `unix` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `miri` --> $DIR/well-known-values.rs:28:7 | LL | #[cfg(miri = "miri")] @@ -39,7 +39,7 @@ LL | #[cfg(miri = "miri")] | = note: no expected value for `miri` -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `linux` --> $DIR/well-known-values.rs:35:7 | LL | #[cfg(doc = "linux")] From 001a65c4b0d82e3cc578f7172accb7bd6673f7e0 Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 12 Oct 2023 17:01:55 +0200 Subject: [PATCH 35/52] check-cfg: only print the list of expected names once --- .../rustc_errors/src/diagnostic_builder.rs | 1 + compiler/rustc_lint/src/context.rs | 6 ++++- tests/ui/check-cfg/mix.stderr | 24 ------------------- 3 files changed, 6 insertions(+), 25 deletions(-) diff --git a/compiler/rustc_errors/src/diagnostic_builder.rs b/compiler/rustc_errors/src/diagnostic_builder.rs index 5e23ae655fe80..85acf8ab5aaef 100644 --- a/compiler/rustc_errors/src/diagnostic_builder.rs +++ b/compiler/rustc_errors/src/diagnostic_builder.rs @@ -659,6 +659,7 @@ impl<'a, G: EmissionGuarantee> DiagnosticBuilder<'a, G> { msg: impl Into, ) -> &mut Self); forward!(pub fn help(&mut self, msg: impl Into) -> &mut Self); + forward!(pub fn help_once(&mut self, msg: impl Into) -> &mut Self); forward!(pub fn span_help( &mut self, sp: impl Into, diff --git a/compiler/rustc_lint/src/context.rs b/compiler/rustc_lint/src/context.rs index 93d155505c417..1ed9b86d66c96 100644 --- a/compiler/rustc_lint/src/context.rs +++ b/compiler/rustc_lint/src/context.rs @@ -758,7 +758,11 @@ pub trait LintContext: Sized { possibilities.sort(); let possibilities = possibilities.join("`, `"); - db.help(format!("expected names are: `{possibilities}`")); + // The list of expected names can be long (even by default) and + // so the diagnostic produced can take a lot of space. To avoid + // cloging the user output we only want to print that diagnostic + // once. + db.help_once(format!("expected names are: `{possibilities}`")); } }, BuiltinLintDiagnostics::UnexpectedCfgValue((name, name_span), value) => { diff --git a/tests/ui/check-cfg/mix.stderr b/tests/ui/check-cfg/mix.stderr index b862239bfdcd7..23da9f22a72c7 100644 --- a/tests/ui/check-cfg/mix.stderr +++ b/tests/ui/check-cfg/mix.stderr @@ -73,24 +73,18 @@ warning: unexpected `cfg` condition name: `xxx` | LL | cfg!(xxx = "foo"); | ^^^^^^^^^^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:48:10 | LL | cfg!(xxx); | ^^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:50:14 | LL | cfg!(any(xxx, windows)); | ^^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition value: `bad` --> $DIR/mix.rs:52:14 @@ -105,48 +99,36 @@ warning: unexpected `cfg` condition name: `xxx` | LL | cfg!(any(windows, xxx)); | ^^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:56:20 | LL | cfg!(all(unix, xxx)); | ^^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name: `aa` --> $DIR/mix.rs:58:14 | LL | cfg!(all(aa, bb)); | ^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name: `bb` --> $DIR/mix.rs:58:18 | LL | cfg!(all(aa, bb)); | ^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name: `aa` --> $DIR/mix.rs:61:14 | LL | cfg!(any(aa, bb)); | ^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name: `bb` --> $DIR/mix.rs:61:18 | LL | cfg!(any(aa, bb)); | ^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition value: `zebra` --> $DIR/mix.rs:64:20 @@ -161,8 +143,6 @@ warning: unexpected `cfg` condition name: `xxx` | LL | cfg!(any(xxx, feature = "zebra")); | ^^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition value: `zebra` --> $DIR/mix.rs:66:19 @@ -177,16 +157,12 @@ warning: unexpected `cfg` condition name: `xxx` | LL | cfg!(any(xxx, unix, xxx)); | ^^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition name: `xxx` --> $DIR/mix.rs:69:25 | LL | cfg!(any(xxx, unix, xxx)); | ^^^ - | - = help: expected names are: `debug_assertions`, `doc`, `doctest`, `feature`, `miri`, `overflow_checks`, `panic`, `proc_macro`, `relocation_model`, `sanitize`, `target_abi`, `target_arch`, `target_endian`, `target_env`, `target_family`, `target_feature`, `target_has_atomic`, `target_has_atomic_equal_alignment`, `target_has_atomic_load_store`, `target_os`, `target_pointer_width`, `target_thread_local`, `target_vendor`, `test`, `unix`, `windows` warning: unexpected `cfg` condition value: `zebra` --> $DIR/mix.rs:72:14 From ed922d8c727979d8fe8b03061e83a0841a0e959b Mon Sep 17 00:00:00 2001 From: Urgau Date: Thu, 12 Oct 2023 18:04:05 +0200 Subject: [PATCH 36/52] check-cfg: update rustdoc ui check-cfg tests --- tests/rustdoc-ui/check-cfg/check-cfg.stderr | 2 +- tests/rustdoc-ui/doctest/check-cfg-test.stderr | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/tests/rustdoc-ui/check-cfg/check-cfg.stderr b/tests/rustdoc-ui/check-cfg/check-cfg.stderr index 03fb6f96fb5f9..d010c1f7ec627 100644 --- a/tests/rustdoc-ui/check-cfg/check-cfg.stderr +++ b/tests/rustdoc-ui/check-cfg/check-cfg.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition name +warning: unexpected `cfg` condition name: `uniz` --> $DIR/check-cfg.rs:5:7 | LL | #[cfg(uniz)] diff --git a/tests/rustdoc-ui/doctest/check-cfg-test.stderr b/tests/rustdoc-ui/doctest/check-cfg-test.stderr index f84543c207254..0bfd569e381eb 100644 --- a/tests/rustdoc-ui/doctest/check-cfg-test.stderr +++ b/tests/rustdoc-ui/doctest/check-cfg-test.stderr @@ -1,4 +1,4 @@ -warning: unexpected `cfg` condition value +warning: unexpected `cfg` condition value: `invalid` --> $DIR/check-cfg-test.rs:9:7 | LL | #[cfg(feature = "invalid")] From f5cdd3e130dce081a72735eeeb0eca283912f48b Mon Sep 17 00:00:00 2001 From: Scott McMurray Date: Thu, 12 Oct 2023 11:03:02 -0700 Subject: [PATCH 37/52] Exclude apple from assembly test --- tests/assembly/x86_64-array-pair-load-store-merge.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/tests/assembly/x86_64-array-pair-load-store-merge.rs b/tests/assembly/x86_64-array-pair-load-store-merge.rs index 4a8e40f85300e..55e317e91bf0b 100644 --- a/tests/assembly/x86_64-array-pair-load-store-merge.rs +++ b/tests/assembly/x86_64-array-pair-load-store-merge.rs @@ -2,6 +2,7 @@ // compile-flags: --crate-type=lib -O -C llvm-args=-x86-asm-syntax=intel // only-x86_64 // ignore-sgx +// ignore-macos (manipulates rsp too) // Depending on various codegen choices, this might end up copying // a `<2 x i8>`, an `i16`, or two `i8`s. From ef8701a4a02e21230401ace80a19169f9f9a6ff8 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 10:01:52 +1100 Subject: [PATCH 38/52] Rename some things. - Rename `pprust` as `pprust_ast`, to align with `pprust_hir`. - Rename `PrinterSupport` as `AstPrinterSupport`, to align with `HirPrinterSupport`. --- compiler/rustc_driver_impl/src/pretty.rs | 70 ++++++++++++------------ 1 file changed, 35 insertions(+), 35 deletions(-) diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 222c7b5d6a72a..5d49c78dea461 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -1,7 +1,7 @@ //! The various pretty-printing routines. use rustc_ast as ast; -use rustc_ast_pretty::pprust; +use rustc_ast_pretty::pprust as pprust_ast; use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir_pretty as pprust_hir; @@ -26,26 +26,25 @@ use crate::abort_on_err; // analysis results) on to the chosen pretty-printer, along with the // `&PpAnn` object. // -// Note that since the `&PrinterSupport` is freshly constructed on each +// Note that since the `&AstPrinterSupport` is freshly constructed on each // call, it would not make sense to try to attach the lifetime of `self` // to the lifetime of the `&PrinterObject`. -/// Constructs a `PrinterSupport` object and passes it to `f`. -fn call_with_pp_support<'tcx, A, F>( +/// Constructs an `AstPrinterSupport` object and passes it to `f`. +fn call_with_pp_support_ast<'tcx, A, F>( ppmode: &PpSourceMode, sess: &'tcx Session, tcx: Option>, f: F, ) -> A where - F: FnOnce(&dyn PrinterSupport) -> A, + F: FnOnce(&dyn AstPrinterSupport) -> A, { match *ppmode { Normal | Expanded => { let annotation = NoAnn { sess, tcx }; f(&annotation) } - Identified | ExpandedIdentified => { let annotation = IdentifiedAnnotation { sess, tcx }; f(&annotation) @@ -65,7 +64,6 @@ where let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) }; f(&annotation, tcx.hir()) } - PpHirMode::Identified => { let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) }; f(&annotation, tcx.hir()) @@ -79,7 +77,7 @@ where } } -trait PrinterSupport: pprust::PpAnn { +trait AstPrinterSupport: pprust_ast::PpAnn { /// Provides a uniform interface for re-extracting a reference to a /// `Session` from a value that now owns it. fn sess(&self) -> &Session; @@ -88,7 +86,7 @@ trait PrinterSupport: pprust::PpAnn { /// /// (Rust does not yet support upcasting from a trait object to /// an object for one of its supertraits.) - fn pp_ann(&self) -> &dyn pprust::PpAnn; + fn pp_ann(&self) -> &dyn pprust_ast::PpAnn; } trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { @@ -112,12 +110,12 @@ struct NoAnn<'hir> { tcx: Option>, } -impl<'hir> PrinterSupport for NoAnn<'hir> { +impl<'hir> AstPrinterSupport for NoAnn<'hir> { fn sess(&self) -> &Session { self.sess } - fn pp_ann(&self) -> &dyn pprust::PpAnn { + fn pp_ann(&self) -> &dyn pprust_ast::PpAnn { self } } @@ -136,7 +134,7 @@ impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { } } -impl<'hir> pprust::PpAnn for NoAnn<'hir> {} +impl<'hir> pprust_ast::PpAnn for NoAnn<'hir> {} impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { if let Some(tcx) = self.tcx { @@ -150,44 +148,46 @@ struct IdentifiedAnnotation<'hir> { tcx: Option>, } -impl<'hir> PrinterSupport for IdentifiedAnnotation<'hir> { +impl<'hir> AstPrinterSupport for IdentifiedAnnotation<'hir> { fn sess(&self) -> &Session { self.sess } - fn pp_ann(&self) -> &dyn pprust::PpAnn { + fn pp_ann(&self) -> &dyn pprust_ast::PpAnn { self } } -impl<'hir> pprust::PpAnn for IdentifiedAnnotation<'hir> { - fn pre(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) { - if let pprust::AnnNode::Expr(_) = node { +impl<'hir> pprust_ast::PpAnn for IdentifiedAnnotation<'hir> { + fn pre(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { + if let pprust_ast::AnnNode::Expr(_) = node { s.popen(); } } - fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) { + fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { match node { - pprust::AnnNode::Crate(_) | pprust::AnnNode::Ident(_) | pprust::AnnNode::Name(_) => {} + pprust_ast::AnnNode::Crate(_) + | pprust_ast::AnnNode::Ident(_) + | pprust_ast::AnnNode::Name(_) => {} - pprust::AnnNode::Item(item) => { + pprust_ast::AnnNode::Item(item) => { s.s.space(); s.synth_comment(item.id.to_string()) } - pprust::AnnNode::SubItem(id) => { + pprust_ast::AnnNode::SubItem(id) => { s.s.space(); s.synth_comment(id.to_string()) } - pprust::AnnNode::Block(blk) => { + pprust_ast::AnnNode::Block(blk) => { s.s.space(); s.synth_comment(format!("block {}", blk.id)) } - pprust::AnnNode::Expr(expr) => { + pprust_ast::AnnNode::Expr(expr) => { s.s.space(); s.synth_comment(expr.id.to_string()); s.pclose() } - pprust::AnnNode::Pat(pat) => { + pprust_ast::AnnNode::Pat(pat) => { s.s.space(); s.synth_comment(format!("pat {}", pat.id)); } @@ -256,28 +256,28 @@ struct HygieneAnnotation<'a> { sess: &'a Session, } -impl<'a> PrinterSupport for HygieneAnnotation<'a> { +impl<'a> AstPrinterSupport for HygieneAnnotation<'a> { fn sess(&self) -> &Session { self.sess } - fn pp_ann(&self) -> &dyn pprust::PpAnn { + fn pp_ann(&self) -> &dyn pprust_ast::PpAnn { self } } -impl<'a> pprust::PpAnn for HygieneAnnotation<'a> { - fn post(&self, s: &mut pprust::State<'_>, node: pprust::AnnNode<'_>) { +impl<'a> pprust_ast::PpAnn for HygieneAnnotation<'a> { + fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { match node { - pprust::AnnNode::Ident(&Ident { name, span }) => { + pprust_ast::AnnNode::Ident(&Ident { name, span }) => { s.s.space(); s.synth_comment(format!("{}{:?}", name.as_u32(), span.ctxt())) } - pprust::AnnNode::Name(&name) => { + pprust_ast::AnnNode::Name(&name) => { s.s.space(); s.synth_comment(name.as_u32().to_string()) } - pprust::AnnNode::Crate(_) => { + pprust_ast::AnnNode::Crate(_) => { s.s.hardbreak(); let verbose = self.sess.verbose(); s.synth_comment(rustc_span::hygiene::debug_hygiene_data(verbose)); @@ -366,11 +366,11 @@ pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) { let out = match ppm { Source(s) => { // Silently ignores an identified node. - call_with_pp_support(&s, sess, None, move |annotation| { + call_with_pp_support_ast(&s, sess, None, move |annotation| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); let parse = &sess.parse_sess; - pprust::print_crate( + pprust_ast::print_crate( sess.source_map(), krate, src_name, @@ -403,11 +403,11 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) { let out = match ppm { Source(s) => { // Silently ignores an identified node. - call_with_pp_support(&s, tcx.sess, Some(tcx), move |annotation| { + call_with_pp_support_ast(&s, tcx.sess, Some(tcx), move |annotation| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); let parse = &sess.parse_sess; - pprust::print_crate( + pprust_ast::print_crate( sess.source_map(), &tcx.resolver_for_lowering(()).borrow().1, src_name, From c5cfcdc4ac0880b171dc0004c660e3a6fd315ee0 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 10:53:12 +1100 Subject: [PATCH 39/52] Remove unnecessary call to `call_with_pp_support_hir`. The callback is trivial and no pp support is actually needed. This makes the `HirTree` case more like the `AstTree` case above. --- compiler/rustc_driver_impl/src/pretty.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 5d49c78dea461..bae0d3dd6a61d 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -441,10 +441,8 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) { }), HirTree => { - call_with_pp_support_hir(&PpHirMode::Normal, tcx, move |_annotation, hir_map| { - debug!("pretty printing HIR tree"); - format!("{:#?}", hir_map.krate()) - }) + debug!("pretty printing HIR tree"); + format!("{:#?}", tcx.hir().krate()) } _ => unreachable!(), From 87090a97e3de431bf15832d9389bf07a969e2791 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 10:54:36 +1100 Subject: [PATCH 40/52] Remove an outdated comment. `phase_3_run_analysis_passes` no longer exists, and AFAICT this code has been refactored so much since this comment was written that it no longer has any useful meaning. --- compiler/rustc_driver_impl/src/pretty.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index bae0d3dd6a61d..4a5198080a20c 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -451,10 +451,6 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) { write_or_print(&out, tcx.sess); } -// In an ideal world, this would be a public function called by the driver after -// analysis is performed. However, we want to call `phase_3_run_analysis_passes` -// with a different callback than the standard driver, so that isn't easy. -// Instead, we call that function ourselves. fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuaranteed> { tcx.analysis(())?; let out = match ppm { From 1467ba06b6b50633541dca9ddebcdacd16a499b1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 12:17:06 +1100 Subject: [PATCH 41/52] Remove PpAstTreeMode. It's simpler to distinguish the two AST modes directly in `PpMode`. --- compiler/rustc_driver_impl/src/pretty.rs | 6 +++--- compiler/rustc_session/src/config.rs | 23 +++++++++-------------- 2 files changed, 12 insertions(+), 17 deletions(-) diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 4a5198080a20c..b258643e97c10 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -8,7 +8,7 @@ use rustc_hir_pretty as pprust_hir; use rustc_middle::hir::map as hir_map; use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; use rustc_middle::ty::{self, TyCtxt}; -use rustc_session::config::{OutFileName, PpAstTreeMode, PpHirMode, PpMode, PpSourceMode}; +use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode}; use rustc_session::Session; use rustc_span::symbol::Ident; use rustc_span::FileName; @@ -382,7 +382,7 @@ pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) { ) }) } - AstTree(PpAstTreeMode::Normal) => { + AstTree => { debug!("pretty printing AST tree"); format!("{krate:#?}") } @@ -420,7 +420,7 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) { }) } - AstTree(PpAstTreeMode::Expanded) => { + AstTreeExpanded => { debug!("pretty-printing expanded AST"); format!("{:#?}", tcx.resolver_for_lowering(()).borrow().1) } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 58461856eb1e7..056986a814418 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -2925,8 +2925,8 @@ fn parse_pretty(handler: &EarlyErrorHandler, unstable_opts: &UnstableOptions) -> "expanded" => Source(PpSourceMode::Expanded), "expanded,identified" => Source(PpSourceMode::ExpandedIdentified), "expanded,hygiene" => Source(PpSourceMode::ExpandedHygiene), - "ast-tree" => AstTree(PpAstTreeMode::Normal), - "ast-tree,expanded" => AstTree(PpAstTreeMode::Expanded), + "ast-tree" => AstTree, + "ast-tree,expanded" => AstTreeExpanded, "hir" => Hir(PpHirMode::Normal), "hir,identified" => Hir(PpHirMode::Identified), "hir,typed" => Hir(PpHirMode::Typed), @@ -3083,14 +3083,6 @@ pub enum PpSourceMode { ExpandedHygiene, } -#[derive(Copy, Clone, PartialEq, Debug)] -pub enum PpAstTreeMode { - /// `-Zunpretty=ast` - Normal, - /// `-Zunpretty=ast,expanded` - Expanded, -} - #[derive(Copy, Clone, PartialEq, Debug)] pub enum PpHirMode { /// `-Zunpretty=hir` @@ -3106,7 +3098,10 @@ pub enum PpMode { /// Options that print the source code, i.e. /// `-Zunpretty=normal` and `-Zunpretty=expanded` Source(PpSourceMode), - AstTree(PpAstTreeMode), + /// `-Zunpretty=ast-tree` + AstTree, + /// `-Zunpretty=ast-tree,expanded` + AstTreeExpanded, /// Options that print the HIR, i.e. `-Zunpretty=hir` Hir(PpHirMode), /// `-Zunpretty=hir-tree` @@ -3126,10 +3121,10 @@ impl PpMode { use PpMode::*; use PpSourceMode::*; match *self { - Source(Normal | Identified) | AstTree(PpAstTreeMode::Normal) => false, + Source(Normal | Identified) | AstTree => false, Source(Expanded | ExpandedIdentified | ExpandedHygiene) - | AstTree(PpAstTreeMode::Expanded) + | AstTreeExpanded | Hir(_) | HirTree | ThirTree @@ -3141,7 +3136,7 @@ impl PpMode { pub fn needs_hir(&self) -> bool { use PpMode::*; match *self { - Source(_) | AstTree(_) => false, + Source(_) | AstTree | AstTreeExpanded => false, Hir(_) | HirTree | ThirTree | ThirFlat | Mir | MirCFG => true, } From d5e7c5f3cc9919bf1ad0b61568d74c65639d4e4e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 12:22:22 +1100 Subject: [PATCH 42/52] Remove unused `PrinterSupport::hir_map` method. --- compiler/rustc_driver_impl/src/pretty.rs | 16 ---------------- 1 file changed, 16 deletions(-) diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index b258643e97c10..b647bf1c31399 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -94,10 +94,6 @@ trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { /// `Session` from a value that now owns it. fn sess(&self) -> &Session; - /// Provides a uniform interface for re-extracting a reference to an - /// `hir_map::Map` from a value that now owns it. - fn hir_map(&self) -> Option>; - /// Produces the pretty-print annotation object. /// /// (Rust does not yet support upcasting from a trait object to @@ -125,10 +121,6 @@ impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { self.sess } - fn hir_map(&self) -> Option> { - self.tcx.map(|tcx| tcx.hir()) - } - fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { self } @@ -200,10 +192,6 @@ impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { self.sess } - fn hir_map(&self) -> Option> { - self.tcx.map(|tcx| tcx.hir()) - } - fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { self } @@ -298,10 +286,6 @@ impl<'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'tcx> { self.tcx.sess } - fn hir_map(&self) -> Option> { - Some(self.tcx.hir()) - } - fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { self } From e3d8bbbfe29ab73afe1d258d6f69c2d6840a30ff Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Tue, 10 Oct 2023 12:58:12 +1100 Subject: [PATCH 43/52] Simplify support traits. First, both `AstPrinterSupport` and `HirPrinterSupport` have a `sess` method. This commit introduces a `Sess` trait and makes the support traits be subtraits of `Sess`, to avoid some duplication. Second, both support traits have a `pp_ann` method that isn't needed if we enable `trait_upcasting`. This commit removes those methods. (Both of these traits will be removed in a subsequent commit, as will the `trait_upcasting` use.) --- compiler/rustc_driver_impl/src/lib.rs | 5 +- compiler/rustc_driver_impl/src/pretty.rs | 95 +++++++----------------- 2 files changed, 30 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 17556c45296ed..bbecf1a1093f0 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -8,10 +8,11 @@ #![cfg_attr(not(bootstrap), doc(rust_logo))] #![cfg_attr(not(bootstrap), feature(rustdoc_internals))] #![cfg_attr(not(bootstrap), allow(internal_features))] -#![feature(lazy_cell)] #![feature(decl_macro)] -#![feature(panic_update_hook)] +#![feature(lazy_cell)] #![feature(let_chains)] +#![feature(panic_update_hook)] +#![feature(trait_upcasting)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index b647bf1c31399..ec118bd33eb92 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -55,9 +55,10 @@ where } } } + fn call_with_pp_support_hir(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A where - F: FnOnce(&dyn HirPrinterSupport<'_>, hir_map::Map<'_>) -> A, + F: FnOnce(&dyn HirPrinterSupport, hir_map::Map<'_>) -> A, { match *ppmode { PpHirMode::Normal => { @@ -77,54 +78,28 @@ where } } -trait AstPrinterSupport: pprust_ast::PpAnn { +trait Sess { /// Provides a uniform interface for re-extracting a reference to a - /// `Session` from a value that now owns it. + /// `Session`. fn sess(&self) -> &Session; - - /// Produces the pretty-print annotation object. - /// - /// (Rust does not yet support upcasting from a trait object to - /// an object for one of its supertraits.) - fn pp_ann(&self) -> &dyn pprust_ast::PpAnn; } -trait HirPrinterSupport<'hir>: pprust_hir::PpAnn { - /// Provides a uniform interface for re-extracting a reference to a - /// `Session` from a value that now owns it. - fn sess(&self) -> &Session; - - /// Produces the pretty-print annotation object. - /// - /// (Rust does not yet support upcasting from a trait object to - /// an object for one of its supertraits.) - fn pp_ann(&self) -> &dyn pprust_hir::PpAnn; -} +trait AstPrinterSupport: pprust_ast::PpAnn + Sess {} +trait HirPrinterSupport: pprust_hir::PpAnn + Sess {} struct NoAnn<'hir> { sess: &'hir Session, tcx: Option>, } -impl<'hir> AstPrinterSupport for NoAnn<'hir> { +impl<'hir> Sess for NoAnn<'hir> { fn sess(&self) -> &Session { self.sess } - - fn pp_ann(&self) -> &dyn pprust_ast::PpAnn { - self - } } -impl<'hir> HirPrinterSupport<'hir> for NoAnn<'hir> { - fn sess(&self) -> &Session { - self.sess - } - - fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { - self - } -} +impl<'tcx> AstPrinterSupport for NoAnn<'tcx> {} +impl<'hir> HirPrinterSupport for NoAnn<'hir> {} impl<'hir> pprust_ast::PpAnn for NoAnn<'hir> {} impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { @@ -140,22 +115,21 @@ struct IdentifiedAnnotation<'hir> { tcx: Option>, } -impl<'hir> AstPrinterSupport for IdentifiedAnnotation<'hir> { +impl<'hir> Sess for IdentifiedAnnotation<'hir> { fn sess(&self) -> &Session { self.sess } - - fn pp_ann(&self) -> &dyn pprust_ast::PpAnn { - self - } } +impl<'hir> AstPrinterSupport for IdentifiedAnnotation<'hir> {} + impl<'hir> pprust_ast::PpAnn for IdentifiedAnnotation<'hir> { fn pre(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { if let pprust_ast::AnnNode::Expr(_) = node { s.popen(); } } + fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { match node { pprust_ast::AnnNode::Crate(_) @@ -187,15 +161,7 @@ impl<'hir> pprust_ast::PpAnn for IdentifiedAnnotation<'hir> { } } -impl<'hir> HirPrinterSupport<'hir> for IdentifiedAnnotation<'hir> { - fn sess(&self) -> &Session { - self.sess - } - - fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { - self - } -} +impl<'hir> HirPrinterSupport for IdentifiedAnnotation<'hir> {} impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { @@ -203,11 +169,13 @@ impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested) } } + fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { if let pprust_hir::AnnNode::Expr(_) = node { s.popen(); } } + fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { match node { pprust_hir::AnnNode::Name(_) => {} @@ -244,16 +212,14 @@ struct HygieneAnnotation<'a> { sess: &'a Session, } -impl<'a> AstPrinterSupport for HygieneAnnotation<'a> { +impl<'a> Sess for HygieneAnnotation<'a> { fn sess(&self) -> &Session { self.sess } - - fn pp_ann(&self) -> &dyn pprust_ast::PpAnn { - self - } } +impl<'a> AstPrinterSupport for HygieneAnnotation<'a> {} + impl<'a> pprust_ast::PpAnn for HygieneAnnotation<'a> { fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { match node { @@ -281,16 +247,14 @@ struct TypedAnnotation<'tcx> { maybe_typeck_results: Cell>>, } -impl<'tcx> HirPrinterSupport<'tcx> for TypedAnnotation<'tcx> { +impl<'tcx> Sess for TypedAnnotation<'tcx> { fn sess(&self) -> &Session { self.tcx.sess } - - fn pp_ann(&self) -> &dyn pprust_hir::PpAnn { - self - } } +impl<'tcx> HirPrinterSupport for TypedAnnotation<'tcx> {} + impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { let old_maybe_typeck_results = self.maybe_typeck_results.get(); @@ -301,11 +265,13 @@ impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> { pprust_hir::PpAnn::nested(pp_ann, state, nested); self.maybe_typeck_results.set(old_maybe_typeck_results); } + fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { if let pprust_hir::AnnNode::Expr(_) = node { s.popen(); } } + fn post(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { if let pprust_hir::AnnNode::Expr(expr) = node { let typeck_results = self.maybe_typeck_results.get().or_else(|| { @@ -359,7 +325,7 @@ pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) { krate, src_name, src, - annotation.pp_ann(), + annotation, false, parse.edition, &sess.parse_sess.attr_id_generator, @@ -396,7 +362,7 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) { &tcx.resolver_for_lowering(()).borrow().1, src_name, src, - annotation.pp_ann(), + annotation, true, parse.edition, &sess.parse_sess.attr_id_generator, @@ -414,14 +380,7 @@ pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) { let sess = annotation.sess(); let sm = sess.source_map(); let attrs = |id| hir_map.attrs(id); - pprust_hir::print_crate( - sm, - hir_map.root_module(), - src_name, - src, - &attrs, - annotation.pp_ann(), - ) + pprust_hir::print_crate(sm, hir_map.root_module(), src_name, src, &attrs, annotation) }), HirTree => { From 7d145a0fde3771662648df2de63e8f64033bf598 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 11 Oct 2023 08:49:24 +1100 Subject: [PATCH 44/52] Merge `print_*` functions. The handling of the `PpMode` variants is currently spread across three functions: `print_after_parsing`, `print_after_hir_lowering`, and `print_with_analysis`. Each one handles some of the variants. This split is primarily because `print_after_parsing` has slightly different arguments to the other two. This commit changes the structure. It merges the three functions into a single `print` function, and encapsulates the different arguments in a new enum `PrintExtra`. Benefits: - The code is a little shorter. - All the `PpMode` variants are handled in a single `match`, with no need for `unreachable!` arms. - It enables the trait removal in the subsequent commit by reducing the number of `call_with_pp_support_ast` call sites from two to one. --- compiler/rustc_driver_impl/src/lib.rs | 4 +- compiler/rustc_driver_impl/src/pretty.rs | 118 ++++++++++------------- 2 files changed, 52 insertions(+), 70 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index bbecf1a1093f0..1cddd561ded00 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -396,7 +396,7 @@ fn run_compiler( if ppm.needs_ast_map() { queries.global_ctxt()?.enter(|tcx| { tcx.ensure().early_lint_checks(()); - pretty::print_after_hir_lowering(tcx, *ppm); + pretty::print(sess, *ppm, pretty::PrintExtra::NeedsAstMap { tcx }); Ok(()) })?; @@ -405,7 +405,7 @@ fn run_compiler( queries.global_ctxt()?.enter(|tcx| tcx.output_filenames(())); } else { let krate = queries.parse()?.steal(); - pretty::print_after_parsing(sess, &krate, *ppm); + pretty::print(sess, *ppm, pretty::PrintExtra::AfterParsing { krate }); } trace!("finished pretty-printing"); return early_exit(); diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index ec118bd33eb92..837f725abe92b 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -2,9 +2,9 @@ use rustc_ast as ast; use rustc_ast_pretty::pprust as pprust_ast; -use rustc_errors::ErrorGuaranteed; use rustc_hir as hir; use rustc_hir_pretty as pprust_hir; +use rustc_middle::bug; use rustc_middle::hir::map as hir_map; use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; use rustc_middle::ty::{self, TyCtxt}; @@ -310,106 +310,92 @@ fn write_or_print(out: &str, sess: &Session) { sess.io.output_file.as_ref().unwrap_or(&OutFileName::Stdout).overwrite(out, sess); } -pub fn print_after_parsing(sess: &Session, krate: &ast::Crate, ppm: PpMode) { - let (src, src_name) = get_source(sess); +// Extra data for pretty-printing, the form of which depends on what kind of +// pretty-printing we are doing. +pub enum PrintExtra<'tcx> { + AfterParsing { krate: ast::Crate }, + NeedsAstMap { tcx: TyCtxt<'tcx> }, +} - let out = match ppm { - Source(s) => { - // Silently ignores an identified node. - call_with_pp_support_ast(&s, sess, None, move |annotation| { - debug!("pretty printing source code {:?}", s); - let sess = annotation.sess(); - let parse = &sess.parse_sess; - pprust_ast::print_crate( - sess.source_map(), - krate, - src_name, - src, - annotation, - false, - parse.edition, - &sess.parse_sess.attr_id_generator, - ) - }) +impl<'tcx> PrintExtra<'tcx> { + fn with_krate(&self, f: F) -> R + where + F: FnOnce(&ast::Crate) -> R + { + match self { + PrintExtra::AfterParsing { krate, .. } => f(krate), + PrintExtra::NeedsAstMap { tcx } => f(&tcx.resolver_for_lowering(()).borrow().1), } - AstTree => { - debug!("pretty printing AST tree"); - format!("{krate:#?}") - } - _ => unreachable!(), - }; + } - write_or_print(&out, sess); + fn tcx(&self) -> TyCtxt<'tcx> { + match self { + PrintExtra::AfterParsing { .. } => bug!("PrintExtra::tcx"), + PrintExtra::NeedsAstMap { tcx } => *tcx, + } + } } -pub fn print_after_hir_lowering<'tcx>(tcx: TyCtxt<'tcx>, ppm: PpMode) { +pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { if ppm.needs_analysis() { - abort_on_err(print_with_analysis(tcx, ppm), tcx.sess); - return; + abort_on_err(ex.tcx().analysis(()), sess); } - let (src, src_name) = get_source(tcx.sess); + let (src, src_name) = get_source(sess); let out = match ppm { Source(s) => { // Silently ignores an identified node. - call_with_pp_support_ast(&s, tcx.sess, Some(tcx), move |annotation| { + call_with_pp_support_ast(&s, sess, None, move |annotation| { debug!("pretty printing source code {:?}", s); let sess = annotation.sess(); let parse = &sess.parse_sess; - pprust_ast::print_crate( - sess.source_map(), - &tcx.resolver_for_lowering(()).borrow().1, - src_name, - src, - annotation, - true, - parse.edition, - &sess.parse_sess.attr_id_generator, + let is_expanded = ppm.needs_ast_map(); + ex.with_krate(|krate| + pprust_ast::print_crate( + sess.source_map(), + krate, + src_name, + src, + annotation, + is_expanded, + parse.edition, + &sess.parse_sess.attr_id_generator, + ) ) }) } - + AstTree => { + debug!("pretty printing AST tree"); + ex.with_krate(|krate| format!("{krate:#?}")) + } AstTreeExpanded => { debug!("pretty-printing expanded AST"); - format!("{:#?}", tcx.resolver_for_lowering(()).borrow().1) + format!("{:#?}", ex.tcx().resolver_for_lowering(()).borrow().1) } - - Hir(s) => call_with_pp_support_hir(&s, tcx, move |annotation, hir_map| { + Hir(s) => call_with_pp_support_hir(&s, ex.tcx(), move |annotation, hir_map| { debug!("pretty printing HIR {:?}", s); let sess = annotation.sess(); let sm = sess.source_map(); let attrs = |id| hir_map.attrs(id); pprust_hir::print_crate(sm, hir_map.root_module(), src_name, src, &attrs, annotation) }), - HirTree => { debug!("pretty printing HIR tree"); - format!("{:#?}", tcx.hir().krate()) + format!("{:#?}", ex.tcx().hir().krate()) } - - _ => unreachable!(), - }; - - write_or_print(&out, tcx.sess); -} - -fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuaranteed> { - tcx.analysis(())?; - let out = match ppm { Mir => { let mut out = Vec::new(); - write_mir_pretty(tcx, None, &mut out).unwrap(); + write_mir_pretty(ex.tcx(), None, &mut out).unwrap(); String::from_utf8(out).unwrap() } - MirCFG => { let mut out = Vec::new(); - write_mir_graphviz(tcx, None, &mut out).unwrap(); + write_mir_graphviz(ex.tcx(), None, &mut out).unwrap(); String::from_utf8(out).unwrap() } - ThirTree => { + let tcx = ex.tcx(); let mut out = String::new(); abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); debug!("pretty printing THIR tree"); @@ -418,8 +404,8 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante } out } - ThirFlat => { + let tcx = ex.tcx(); let mut out = String::new(); abort_on_err(rustc_hir_analysis::check_crate(tcx), tcx.sess); debug!("pretty printing THIR flat"); @@ -428,11 +414,7 @@ fn print_with_analysis(tcx: TyCtxt<'_>, ppm: PpMode) -> Result<(), ErrorGuarante } out } - - _ => unreachable!(), }; - write_or_print(&out, tcx.sess); - - Ok(()) + write_or_print(&out, sess); } From 060851b7646dff523c25958930b2a7cbe6ce91a1 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 11 Oct 2023 08:55:41 +1100 Subject: [PATCH 45/52] Remove pretty-printing traits. `call_with_pp_support_ast` and `call_with_pp_support_hir` how each have a single call site. This commit inlines and removes them, which also removes the need for all the supporting traits: `Sess`, `AstPrinterSupport`, and `HirPrinterSupport`. The `sess` member is also removed from several structs. --- compiler/rustc_driver_impl/src/lib.rs | 1 - compiler/rustc_driver_impl/src/pretty.rs | 181 +++++++---------------- 2 files changed, 52 insertions(+), 130 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 1cddd561ded00..4074d57433ef6 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -12,7 +12,6 @@ #![feature(lazy_cell)] #![feature(let_chains)] #![feature(panic_update_hook)] -#![feature(trait_upcasting)] #![recursion_limit = "256"] #![allow(rustc::potential_query_instability)] #![deny(rustc::untranslatable_diagnostic)] diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 837f725abe92b..4145b5baeb01b 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -5,7 +5,6 @@ use rustc_ast_pretty::pprust as pprust_ast; use rustc_hir as hir; use rustc_hir_pretty as pprust_hir; use rustc_middle::bug; -use rustc_middle::hir::map as hir_map; use rustc_middle::mir::{write_mir_graphviz, write_mir_pretty}; use rustc_middle::ty::{self, TyCtxt}; use rustc_session::config::{OutFileName, PpHirMode, PpMode, PpSourceMode}; @@ -20,87 +19,10 @@ pub use self::PpMode::*; pub use self::PpSourceMode::*; use crate::abort_on_err; -// This slightly awkward construction is to allow for each PpMode to -// choose whether it needs to do analyses (which can consume the -// Session) and then pass through the session (now attached to the -// analysis results) on to the chosen pretty-printer, along with the -// `&PpAnn` object. -// -// Note that since the `&AstPrinterSupport` is freshly constructed on each -// call, it would not make sense to try to attach the lifetime of `self` -// to the lifetime of the `&PrinterObject`. - -/// Constructs an `AstPrinterSupport` object and passes it to `f`. -fn call_with_pp_support_ast<'tcx, A, F>( - ppmode: &PpSourceMode, - sess: &'tcx Session, - tcx: Option>, - f: F, -) -> A -where - F: FnOnce(&dyn AstPrinterSupport) -> A, -{ - match *ppmode { - Normal | Expanded => { - let annotation = NoAnn { sess, tcx }; - f(&annotation) - } - Identified | ExpandedIdentified => { - let annotation = IdentifiedAnnotation { sess, tcx }; - f(&annotation) - } - ExpandedHygiene => { - let annotation = HygieneAnnotation { sess }; - f(&annotation) - } - } -} - -fn call_with_pp_support_hir(ppmode: &PpHirMode, tcx: TyCtxt<'_>, f: F) -> A -where - F: FnOnce(&dyn HirPrinterSupport, hir_map::Map<'_>) -> A, -{ - match *ppmode { - PpHirMode::Normal => { - let annotation = NoAnn { sess: tcx.sess, tcx: Some(tcx) }; - f(&annotation, tcx.hir()) - } - PpHirMode::Identified => { - let annotation = IdentifiedAnnotation { sess: tcx.sess, tcx: Some(tcx) }; - f(&annotation, tcx.hir()) - } - PpHirMode::Typed => { - abort_on_err(tcx.analysis(()), tcx.sess); - - let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) }; - tcx.dep_graph.with_ignore(|| f(&annotation, tcx.hir())) - } - } -} - -trait Sess { - /// Provides a uniform interface for re-extracting a reference to a - /// `Session`. - fn sess(&self) -> &Session; -} - -trait AstPrinterSupport: pprust_ast::PpAnn + Sess {} -trait HirPrinterSupport: pprust_hir::PpAnn + Sess {} - struct NoAnn<'hir> { - sess: &'hir Session, tcx: Option>, } -impl<'hir> Sess for NoAnn<'hir> { - fn sess(&self) -> &Session { - self.sess - } -} - -impl<'tcx> AstPrinterSupport for NoAnn<'tcx> {} -impl<'hir> HirPrinterSupport for NoAnn<'hir> {} - impl<'hir> pprust_ast::PpAnn for NoAnn<'hir> {} impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { @@ -111,18 +33,9 @@ impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { } struct IdentifiedAnnotation<'hir> { - sess: &'hir Session, tcx: Option>, } -impl<'hir> Sess for IdentifiedAnnotation<'hir> { - fn sess(&self) -> &Session { - self.sess - } -} - -impl<'hir> AstPrinterSupport for IdentifiedAnnotation<'hir> {} - impl<'hir> pprust_ast::PpAnn for IdentifiedAnnotation<'hir> { fn pre(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { if let pprust_ast::AnnNode::Expr(_) = node { @@ -161,8 +74,6 @@ impl<'hir> pprust_ast::PpAnn for IdentifiedAnnotation<'hir> { } } -impl<'hir> HirPrinterSupport for IdentifiedAnnotation<'hir> {} - impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { if let Some(ref tcx) = self.tcx { @@ -212,14 +123,6 @@ struct HygieneAnnotation<'a> { sess: &'a Session, } -impl<'a> Sess for HygieneAnnotation<'a> { - fn sess(&self) -> &Session { - self.sess - } -} - -impl<'a> AstPrinterSupport for HygieneAnnotation<'a> {} - impl<'a> pprust_ast::PpAnn for HygieneAnnotation<'a> { fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { match node { @@ -247,14 +150,6 @@ struct TypedAnnotation<'tcx> { maybe_typeck_results: Cell>>, } -impl<'tcx> Sess for TypedAnnotation<'tcx> { - fn sess(&self) -> &Session { - self.tcx.sess - } -} - -impl<'tcx> HirPrinterSupport for TypedAnnotation<'tcx> {} - impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { let old_maybe_typeck_results = self.maybe_typeck_results.get(); @@ -320,7 +215,7 @@ pub enum PrintExtra<'tcx> { impl<'tcx> PrintExtra<'tcx> { fn with_krate(&self, f: F) -> R where - F: FnOnce(&ast::Crate) -> R + F: FnOnce(&ast::Crate) -> R, { match self { PrintExtra::AfterParsing { krate, .. } => f(krate), @@ -345,23 +240,26 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { let out = match ppm { Source(s) => { - // Silently ignores an identified node. - call_with_pp_support_ast(&s, sess, None, move |annotation| { - debug!("pretty printing source code {:?}", s); - let sess = annotation.sess(); - let parse = &sess.parse_sess; - let is_expanded = ppm.needs_ast_map(); - ex.with_krate(|krate| - pprust_ast::print_crate( - sess.source_map(), - krate, - src_name, - src, - annotation, - is_expanded, - parse.edition, - &sess.parse_sess.attr_id_generator, - ) + debug!("pretty printing source code {:?}", s); + let annotation: Box = match s { + Normal => Box::new(NoAnn { tcx: None }), + Expanded => Box::new(NoAnn { tcx: Some(ex.tcx()) }), + Identified => Box::new(IdentifiedAnnotation { tcx: None }), + ExpandedIdentified => Box::new(IdentifiedAnnotation { tcx: Some(ex.tcx()) }), + ExpandedHygiene => Box::new(HygieneAnnotation { sess }), + }; + let parse = &sess.parse_sess; + let is_expanded = ppm.needs_ast_map(); + ex.with_krate(|krate| { + pprust_ast::print_crate( + sess.source_map(), + krate, + src_name, + src, + &*annotation, + is_expanded, + parse.edition, + &sess.parse_sess.attr_id_generator, ) }) } @@ -373,13 +271,38 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { debug!("pretty-printing expanded AST"); format!("{:#?}", ex.tcx().resolver_for_lowering(()).borrow().1) } - Hir(s) => call_with_pp_support_hir(&s, ex.tcx(), move |annotation, hir_map| { + Hir(s) => { debug!("pretty printing HIR {:?}", s); - let sess = annotation.sess(); - let sm = sess.source_map(); - let attrs = |id| hir_map.attrs(id); - pprust_hir::print_crate(sm, hir_map.root_module(), src_name, src, &attrs, annotation) - }), + let tcx = ex.tcx(); + let f = |annotation: &dyn pprust_hir::PpAnn| { + let sm = sess.source_map(); + let hir_map = tcx.hir(); + let attrs = |id| hir_map.attrs(id); + pprust_hir::print_crate( + sm, + hir_map.root_module(), + src_name, + src, + &attrs, + annotation, + ) + }; + match s { + PpHirMode::Normal => { + let annotation = NoAnn { tcx: Some(tcx) }; + f(&annotation) + } + PpHirMode::Identified => { + let annotation = IdentifiedAnnotation { tcx: Some(tcx) }; + f(&annotation) + } + PpHirMode::Typed => { + abort_on_err(tcx.analysis(()), tcx.sess); + let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) }; + tcx.dep_graph.with_ignore(|| f(&annotation)) + } + } + } HirTree => { debug!("pretty printing HIR tree"); format!("{:#?}", ex.tcx().hir().krate()) From ba58e3213db9626381f5fd014e569f7d2335fa03 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 11 Oct 2023 08:58:27 +1100 Subject: [PATCH 46/52] Rename some `'hir` lifetimes as `'tcx`. Because they all end up within a `TyCtxt`. --- compiler/rustc_driver_impl/src/pretty.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 4145b5baeb01b..daba78612f5c7 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -19,12 +19,12 @@ pub use self::PpMode::*; pub use self::PpSourceMode::*; use crate::abort_on_err; -struct NoAnn<'hir> { - tcx: Option>, +struct NoAnn<'tcx> { + tcx: Option>, } -impl<'hir> pprust_ast::PpAnn for NoAnn<'hir> {} -impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { +impl<'tcx> pprust_ast::PpAnn for NoAnn<'tcx> {} +impl<'tcx> pprust_hir::PpAnn for NoAnn<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { if let Some(tcx) = self.tcx { pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested) @@ -32,11 +32,11 @@ impl<'hir> pprust_hir::PpAnn for NoAnn<'hir> { } } -struct IdentifiedAnnotation<'hir> { - tcx: Option>, +struct IdentifiedAnnotation<'tcx> { + tcx: Option>, } -impl<'hir> pprust_ast::PpAnn for IdentifiedAnnotation<'hir> { +impl<'tcx> pprust_ast::PpAnn for IdentifiedAnnotation<'tcx> { fn pre(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { if let pprust_ast::AnnNode::Expr(_) = node { s.popen(); @@ -74,7 +74,7 @@ impl<'hir> pprust_ast::PpAnn for IdentifiedAnnotation<'hir> { } } -impl<'hir> pprust_hir::PpAnn for IdentifiedAnnotation<'hir> { +impl<'tcx> pprust_hir::PpAnn for IdentifiedAnnotation<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { if let Some(ref tcx) = self.tcx { pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested) From b65227a9ee38cd21e0b4ffbec7542d2638b661a2 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 11 Oct 2023 09:31:43 +1100 Subject: [PATCH 47/52] Make `needs_analysis` true for `PpHirMode::Typed`. This avoids the need for a bespoke `tcx.analysis()` call. --- compiler/rustc_driver_impl/src/pretty.rs | 1 - compiler/rustc_session/src/config.rs | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index daba78612f5c7..87e3af2f9d9c8 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -297,7 +297,6 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { f(&annotation) } PpHirMode::Typed => { - abort_on_err(tcx.analysis(()), tcx.sess); let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) }; tcx.dep_graph.with_ignore(|| f(&annotation)) } diff --git a/compiler/rustc_session/src/config.rs b/compiler/rustc_session/src/config.rs index 056986a814418..2a6f5994c4905 100644 --- a/compiler/rustc_session/src/config.rs +++ b/compiler/rustc_session/src/config.rs @@ -3144,7 +3144,7 @@ impl PpMode { pub fn needs_analysis(&self) -> bool { use PpMode::*; - matches!(*self, Mir | MirCFG | ThirTree | ThirFlat) + matches!(*self, Hir(PpHirMode::Typed) | Mir | MirCFG | ThirTree | ThirFlat) } } From 2e2924f2631bebbf2e0f5f40e26bf5d8d032c6d4 Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Wed, 11 Oct 2023 09:47:15 +1100 Subject: [PATCH 48/52] Split and rename the annotation structs. `NoAnn` and `IdentifiedAnnotation` impl both `pprust_ast::PpAnn` and `pprust_hir::PpAnn`, which is a bit confusing, because the optional `tcx` is only needed for the HIR cases. (Currently the `tcx` is unnecessarily provided in the `expanded` AST cases.) This commit splits each one into `Ast` and `Hir` versions, which makes things clear about where the `tcx` is needed. The commit also renames all the traits so they consistently end with `Ann`. --- compiler/rustc_driver_impl/src/pretty.rs | 63 ++++++++++++++---------- 1 file changed, 36 insertions(+), 27 deletions(-) diff --git a/compiler/rustc_driver_impl/src/pretty.rs b/compiler/rustc_driver_impl/src/pretty.rs index 87e3af2f9d9c8..8c6fee8301301 100644 --- a/compiler/rustc_driver_impl/src/pretty.rs +++ b/compiler/rustc_driver_impl/src/pretty.rs @@ -19,24 +19,27 @@ pub use self::PpMode::*; pub use self::PpSourceMode::*; use crate::abort_on_err; -struct NoAnn<'tcx> { - tcx: Option>, +struct AstNoAnn; + +impl pprust_ast::PpAnn for AstNoAnn {} + +struct HirNoAnn<'tcx> { + tcx: TyCtxt<'tcx>, } -impl<'tcx> pprust_ast::PpAnn for NoAnn<'tcx> {} -impl<'tcx> pprust_hir::PpAnn for NoAnn<'tcx> { +impl<'tcx> pprust_hir::PpAnn for HirNoAnn<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { - if let Some(tcx) = self.tcx { - pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested) - } + pprust_hir::PpAnn::nested( + &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>), + state, + nested, + ) } } -struct IdentifiedAnnotation<'tcx> { - tcx: Option>, -} +struct AstIdentifiedAnn; -impl<'tcx> pprust_ast::PpAnn for IdentifiedAnnotation<'tcx> { +impl pprust_ast::PpAnn for AstIdentifiedAnn { fn pre(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { if let pprust_ast::AnnNode::Expr(_) = node { s.popen(); @@ -74,11 +77,17 @@ impl<'tcx> pprust_ast::PpAnn for IdentifiedAnnotation<'tcx> { } } -impl<'tcx> pprust_hir::PpAnn for IdentifiedAnnotation<'tcx> { +struct HirIdentifiedAnn<'tcx> { + tcx: TyCtxt<'tcx>, +} + +impl<'tcx> pprust_hir::PpAnn for HirIdentifiedAnn<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { - if let Some(ref tcx) = self.tcx { - pprust_hir::PpAnn::nested(&(&tcx.hir() as &dyn hir::intravisit::Map<'_>), state, nested) - } + pprust_hir::PpAnn::nested( + &(&self.tcx.hir() as &dyn hir::intravisit::Map<'_>), + state, + nested, + ) } fn pre(&self, s: &mut pprust_hir::State<'_>, node: pprust_hir::AnnNode<'_>) { @@ -119,11 +128,11 @@ impl<'tcx> pprust_hir::PpAnn for IdentifiedAnnotation<'tcx> { } } -struct HygieneAnnotation<'a> { +struct AstHygieneAnn<'a> { sess: &'a Session, } -impl<'a> pprust_ast::PpAnn for HygieneAnnotation<'a> { +impl<'a> pprust_ast::PpAnn for AstHygieneAnn<'a> { fn post(&self, s: &mut pprust_ast::State<'_>, node: pprust_ast::AnnNode<'_>) { match node { pprust_ast::AnnNode::Ident(&Ident { name, span }) => { @@ -145,12 +154,12 @@ impl<'a> pprust_ast::PpAnn for HygieneAnnotation<'a> { } } -struct TypedAnnotation<'tcx> { +struct HirTypedAnn<'tcx> { tcx: TyCtxt<'tcx>, maybe_typeck_results: Cell>>, } -impl<'tcx> pprust_hir::PpAnn for TypedAnnotation<'tcx> { +impl<'tcx> pprust_hir::PpAnn for HirTypedAnn<'tcx> { fn nested(&self, state: &mut pprust_hir::State<'_>, nested: pprust_hir::Nested) { let old_maybe_typeck_results = self.maybe_typeck_results.get(); if let pprust_hir::Nested::Body(id) = nested { @@ -242,11 +251,11 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { Source(s) => { debug!("pretty printing source code {:?}", s); let annotation: Box = match s { - Normal => Box::new(NoAnn { tcx: None }), - Expanded => Box::new(NoAnn { tcx: Some(ex.tcx()) }), - Identified => Box::new(IdentifiedAnnotation { tcx: None }), - ExpandedIdentified => Box::new(IdentifiedAnnotation { tcx: Some(ex.tcx()) }), - ExpandedHygiene => Box::new(HygieneAnnotation { sess }), + Normal => Box::new(AstNoAnn), + Expanded => Box::new(AstNoAnn), + Identified => Box::new(AstIdentifiedAnn), + ExpandedIdentified => Box::new(AstIdentifiedAnn), + ExpandedHygiene => Box::new(AstHygieneAnn { sess }), }; let parse = &sess.parse_sess; let is_expanded = ppm.needs_ast_map(); @@ -289,15 +298,15 @@ pub fn print<'tcx>(sess: &Session, ppm: PpMode, ex: PrintExtra<'tcx>) { }; match s { PpHirMode::Normal => { - let annotation = NoAnn { tcx: Some(tcx) }; + let annotation = HirNoAnn { tcx }; f(&annotation) } PpHirMode::Identified => { - let annotation = IdentifiedAnnotation { tcx: Some(tcx) }; + let annotation = HirIdentifiedAnn { tcx }; f(&annotation) } PpHirMode::Typed => { - let annotation = TypedAnnotation { tcx, maybe_typeck_results: Cell::new(None) }; + let annotation = HirTypedAnn { tcx, maybe_typeck_results: Cell::new(None) }; tcx.dep_graph.with_ignore(|| f(&annotation)) } } From 2b4c33817a5aaecabf4c6598d41e190080ec119e Mon Sep 17 00:00:00 2001 From: Nicholas Nethercote Date: Fri, 6 Oct 2023 18:15:46 +1100 Subject: [PATCH 49/52] Remove unneeded `pub`s. --- compiler/rustc_driver_impl/src/lib.rs | 14 +++++++------- 1 file changed, 7 insertions(+), 7 deletions(-) diff --git a/compiler/rustc_driver_impl/src/lib.rs b/compiler/rustc_driver_impl/src/lib.rs index 4074d57433ef6..7a45ac10f0ba9 100644 --- a/compiler/rustc_driver_impl/src/lib.rs +++ b/compiler/rustc_driver_impl/src/lib.rs @@ -545,7 +545,7 @@ pub enum Compilation { } impl Compilation { - pub fn and_then Compilation>(self, next: F) -> Compilation { + fn and_then Compilation>(self, next: F) -> Compilation { match self { Compilation::Stop => Compilation::Stop, Compilation::Continue => next(), @@ -657,7 +657,7 @@ fn show_md_content_with_pager(content: &str, color: ColorConfig) { } } -pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation { +fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Compilation { if sess.opts.unstable_opts.link_only { if let Input::File(file) = &sess.io.input { let outputs = compiler.build_output_filenames(sess, &[]); @@ -698,7 +698,7 @@ pub fn try_process_rlink(sess: &Session, compiler: &interface::Compiler) -> Comp } } -pub fn list_metadata( +fn list_metadata( handler: &EarlyErrorHandler, sess: &Session, metadata_loader: &dyn MetadataLoader, @@ -1184,7 +1184,7 @@ fn print_flag_list( /// /// So with all that in mind, the comments below have some more detail about the /// contortions done here to get things to work out correctly. -pub fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option { +fn handle_options(handler: &EarlyErrorHandler, args: &[String]) -> Option { if args.is_empty() { // user did not write `-v` nor `-Z unstable-options`, so do not // include that extra information. @@ -1283,9 +1283,9 @@ pub fn catch_with_exit_code(f: impl FnOnce() -> interface::Result<()>) -> i32 { } } -pub static ICE_PATH: OnceLock> = OnceLock::new(); +static ICE_PATH: OnceLock> = OnceLock::new(); -pub fn ice_path() -> &'static Option { +fn ice_path() -> &'static Option { ICE_PATH.get_or_init(|| { if !rustc_feature::UnstableFeatures::from_environment(None).is_nightly_build() { return None; @@ -1394,7 +1394,7 @@ pub fn install_ice_hook(bug_report_url: &'static str, extra_info: fn(&Handler)) /// /// When `install_ice_hook` is called, this function will be called as the panic /// hook. -pub fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) { +fn report_ice(info: &panic::PanicInfo<'_>, bug_report_url: &str, extra_info: fn(&Handler)) { let fallback_bundle = rustc_errors::fallback_fluent_bundle(crate::DEFAULT_LOCALE_RESOURCES.to_vec(), false); let emitter = Box::new(rustc_errors::emitter::EmitterWriter::stderr( From 8447df360ad35101029636bfa2d128b18454a83f Mon Sep 17 00:00:00 2001 From: bohan Date: Thu, 12 Oct 2023 21:58:54 +0800 Subject: [PATCH 50/52] use effective_visibilities to check unused --- compiler/rustc_ast/src/lib.rs | 1 - .../rustc_codegen_llvm/src/debuginfo/mod.rs | 1 - compiler/rustc_codegen_llvm/src/mono_item.rs | 1 - compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs | 2 - compiler/rustc_infer/src/traits/mod.rs | 1 - compiler/rustc_middle/src/mir/terminator.rs | 2 - compiler/rustc_middle/src/ty/assoc.rs | 2 - .../rustc_mir_dataflow/src/framework/mod.rs | 2 +- compiler/rustc_resolve/src/check_unused.rs | 2 +- .../src/traits/error_reporting/mod.rs | 1 - .../rustc_trait_selection/src/traits/mod.rs | 5 --- .../rustc_trait_selection/src/traits/util.rs | 2 +- .../portable-simd/crates/core_simd/src/mod.rs | 1 - library/std/src/sys/unix/process/mod.rs | 1 - .../crates/parser/src/syntax_kind.rs | 2 +- .../parser/src/syntax_kind/generated.rs | 1 - tests/ui/imports/pub-reexport-empty.rs | 25 ++++++++++++ tests/ui/imports/pub-reexport-empty.stderr | 20 ++++++++++ tests/ui/imports/reexports.rs | 5 ++- tests/ui/imports/reexports.stderr | 34 +++++++++++------ tests/ui/lint/unused/lint-unused-imports.rs | 2 +- .../ui/lint/unused/lint-unused-imports.stderr | 8 +++- .../recover-missing-semi-before-item.fixed | 2 +- .../recover-missing-semi-before-item.rs | 2 +- ...sue-46209-private-enum-variant-reexport.rs | 4 ++ ...46209-private-enum-variant-reexport.stderr | 38 +++++++++++++++---- tests/ui/privacy/private-variant-reexport.rs | 4 +- .../privacy/private-variant-reexport.stderr | 8 +++- 28 files changed, 131 insertions(+), 48 deletions(-) create mode 100644 tests/ui/imports/pub-reexport-empty.rs create mode 100644 tests/ui/imports/pub-reexport-empty.stderr diff --git a/compiler/rustc_ast/src/lib.rs b/compiler/rustc_ast/src/lib.rs index ddc7c8ee82583..73af6bd1550a0 100644 --- a/compiler/rustc_ast/src/lib.rs +++ b/compiler/rustc_ast/src/lib.rs @@ -53,7 +53,6 @@ pub mod visit; pub use self::ast::*; pub use self::ast_traits::{AstDeref, AstNodeWrapper, HasAttrs, HasNodeId, HasSpan, HasTokens}; -pub use self::format::*; use rustc_data_structures::stable_hasher::{HashStable, StableHasher}; diff --git a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs index 30cc9ea9b8258..6d64862625ded 100644 --- a/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs +++ b/compiler/rustc_codegen_llvm/src/debuginfo/mod.rs @@ -50,7 +50,6 @@ mod utils; pub use self::create_scope_map::compute_mir_scopes; pub use self::metadata::build_global_var_di_node; -pub use self::metadata::extend_scope_to_file; #[allow(non_upper_case_globals)] const DW_TAG_auto_variable: c_uint = 0x100; diff --git a/compiler/rustc_codegen_llvm/src/mono_item.rs b/compiler/rustc_codegen_llvm/src/mono_item.rs index 38e8220569a2a..01e823396646c 100644 --- a/compiler/rustc_codegen_llvm/src/mono_item.rs +++ b/compiler/rustc_codegen_llvm/src/mono_item.rs @@ -6,7 +6,6 @@ use crate::llvm; use crate::type_of::LayoutLlvmExt; use rustc_codegen_ssa::traits::*; use rustc_hir::def_id::{DefId, LOCAL_CRATE}; -pub use rustc_middle::mir::mono::MonoItem; use rustc_middle::mir::mono::{Linkage, Visibility}; use rustc_middle::ty::layout::{FnAbiOf, LayoutOf}; use rustc_middle::ty::{self, Instance, TypeVisitableExt}; diff --git a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs index 4a245d30c8e39..bca35c7b4c8bf 100644 --- a/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs +++ b/compiler/rustc_hir_typeck/src/fn_ctxt/mod.rs @@ -4,9 +4,7 @@ mod arg_matrix; mod checks; mod suggestions; -pub use _impl::*; use rustc_errors::ErrorGuaranteed; -pub use suggestions::*; use crate::coercion::DynamicCoerceMany; use crate::{Diverges, EnclosingBreakables, Inherited}; diff --git a/compiler/rustc_infer/src/traits/mod.rs b/compiler/rustc_infer/src/traits/mod.rs index a5b2ccce85e1e..a26e676c52175 100644 --- a/compiler/rustc_infer/src/traits/mod.rs +++ b/compiler/rustc_infer/src/traits/mod.rs @@ -19,7 +19,6 @@ use rustc_span::Span; pub use self::FulfillmentErrorCode::*; pub use self::ImplSource::*; -pub use self::ObligationCauseCode::*; pub use self::SelectionError::*; pub use self::engine::{TraitEngine, TraitEngineExt}; diff --git a/compiler/rustc_middle/src/mir/terminator.rs b/compiler/rustc_middle/src/mir/terminator.rs index 02aab4a892d05..4866ae8e69b83 100644 --- a/compiler/rustc_middle/src/mir/terminator.rs +++ b/compiler/rustc_middle/src/mir/terminator.rs @@ -3,12 +3,10 @@ use rustc_hir::LangItem; use smallvec::SmallVec; use super::{BasicBlock, InlineAsmOperand, Operand, SourceInfo, TerminatorKind, UnwindAction}; -pub use rustc_ast::Mutability; use rustc_macros::HashStable; use std::iter; use std::slice; -pub use super::query::*; use super::*; impl SwitchTargets { diff --git a/compiler/rustc_middle/src/ty/assoc.rs b/compiler/rustc_middle/src/ty/assoc.rs index f77a8c6712efa..94a5ff13158a2 100644 --- a/compiler/rustc_middle/src/ty/assoc.rs +++ b/compiler/rustc_middle/src/ty/assoc.rs @@ -1,5 +1,3 @@ -pub use self::AssocItemContainer::*; - use crate::ty; use rustc_data_structures::sorted_map::SortedIndexMultiMap; use rustc_hir as hir; diff --git a/compiler/rustc_mir_dataflow/src/framework/mod.rs b/compiler/rustc_mir_dataflow/src/framework/mod.rs index ce30c642fcc9f..70821637acf8e 100644 --- a/compiler/rustc_mir_dataflow/src/framework/mod.rs +++ b/compiler/rustc_mir_dataflow/src/framework/mod.rs @@ -48,7 +48,7 @@ mod visitor; pub use self::cursor::{AnalysisResults, ResultsClonedCursor, ResultsCursor, ResultsRefCursor}; pub use self::direction::{Backward, Direction, Forward}; pub use self::engine::{Engine, EntrySets, Results, ResultsCloned}; -pub use self::lattice::{JoinSemiLattice, MaybeReachable, MeetSemiLattice}; +pub use self::lattice::{JoinSemiLattice, MaybeReachable}; pub use self::visitor::{visit_results, ResultsVisitable, ResultsVisitor}; /// Analysis domains are all bitsets of various kinds. This trait holds diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index 7dbbd4c34ea7d..baa7d87039954 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -173,7 +173,7 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { self.base_use_tree = Some(use_tree); } - if self.base_use_is_pub { + if self.r.effective_visibilities.is_exported(self.r.local_def_id(id)) { self.check_import_as_underscore(use_tree, id); return; } diff --git a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs index 989c1310b76c8..79b09db2268b6 100644 --- a/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/error_reporting/mod.rs @@ -20,7 +20,6 @@ use std::ops::ControlFlow; pub use self::infer_ctxt_ext::*; pub use self::type_err_ctxt_ext::*; -pub use rustc_infer::traits::error_reporting::*; // When outputting impl candidates, prefer showing those that are more similar. // diff --git a/compiler/rustc_trait_selection/src/traits/mod.rs b/compiler/rustc_trait_selection/src/traits/mod.rs index ab81d77a268d8..71007e1f0e0a7 100644 --- a/compiler/rustc_trait_selection/src/traits/mod.rs +++ b/compiler/rustc_trait_selection/src/traits/mod.rs @@ -41,11 +41,6 @@ use std::ops::ControlFlow; pub(crate) use self::project::{needs_normalization, BoundVarReplacer, PlaceholderReplacer}; -pub use self::FulfillmentErrorCode::*; -pub use self::ImplSource::*; -pub use self::ObligationCauseCode::*; -pub use self::SelectionError::*; - pub use self::coherence::{add_placeholder_note, orphan_check, overlapping_impls}; pub use self::coherence::{OrphanCheckErr, OverlapResult}; pub use self::engine::{ObligationCtxt, TraitEngineExt}; diff --git a/compiler/rustc_trait_selection/src/traits/util.rs b/compiler/rustc_trait_selection/src/traits/util.rs index a76272e9d092d..8be2ac5a8364e 100644 --- a/compiler/rustc_trait_selection/src/traits/util.rs +++ b/compiler/rustc_trait_selection/src/traits/util.rs @@ -9,7 +9,7 @@ use rustc_middle::ty::{self, ImplSubject, ToPredicate, Ty, TyCtxt, TypeVisitable use rustc_span::Span; use smallvec::SmallVec; -pub use rustc_infer::traits::{self, util::*}; +pub use rustc_infer::traits::util::*; /////////////////////////////////////////////////////////////////////////// // `TraitAliasExpander` iterator diff --git a/library/portable-simd/crates/core_simd/src/mod.rs b/library/portable-simd/crates/core_simd/src/mod.rs index f9891a3b7c1d7..19426769858b0 100644 --- a/library/portable-simd/crates/core_simd/src/mod.rs +++ b/library/portable-simd/crates/core_simd/src/mod.rs @@ -35,6 +35,5 @@ pub mod simd { pub use crate::core_simd::masks::*; pub use crate::core_simd::ord::*; pub use crate::core_simd::swizzle::*; - pub use crate::core_simd::swizzle_dyn::*; pub use crate::core_simd::vector::*; } diff --git a/library/std/src/sys/unix/process/mod.rs b/library/std/src/sys/unix/process/mod.rs index 0cf163d9fb8e9..b8dd90ddfb8fc 100644 --- a/library/std/src/sys/unix/process/mod.rs +++ b/library/std/src/sys/unix/process/mod.rs @@ -1,7 +1,6 @@ pub use self::process_common::{Command, CommandArgs, ExitCode, Stdio, StdioPipes}; pub use self::process_inner::{ExitStatus, ExitStatusError, Process}; pub use crate::ffi::OsString as EnvKey; -pub use crate::sys_common::process::CommandEnvs; #[cfg_attr(any(target_os = "espidf", target_os = "horizon"), allow(unused))] mod process_common; diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs index 0483adc776fa6..3ca6bd4cb111c 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind.rs @@ -4,7 +4,7 @@ mod generated; #[allow(unreachable_pub)] -pub use self::generated::{SyntaxKind, T}; +pub use self::generated::SyntaxKind; impl From for SyntaxKind { #[inline] diff --git a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs index db5278f89d560..4b589037672f4 100644 --- a/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs +++ b/src/tools/rust-analyzer/crates/parser/src/syntax_kind/generated.rs @@ -497,4 +497,3 @@ impl SyntaxKind { } #[macro_export] macro_rules ! T { [;] => { $ crate :: SyntaxKind :: SEMICOLON } ; [,] => { $ crate :: SyntaxKind :: COMMA } ; ['('] => { $ crate :: SyntaxKind :: L_PAREN } ; [')'] => { $ crate :: SyntaxKind :: R_PAREN } ; ['{'] => { $ crate :: SyntaxKind :: L_CURLY } ; ['}'] => { $ crate :: SyntaxKind :: R_CURLY } ; ['['] => { $ crate :: SyntaxKind :: L_BRACK } ; [']'] => { $ crate :: SyntaxKind :: R_BRACK } ; [<] => { $ crate :: SyntaxKind :: L_ANGLE } ; [>] => { $ crate :: SyntaxKind :: R_ANGLE } ; [@] => { $ crate :: SyntaxKind :: AT } ; [#] => { $ crate :: SyntaxKind :: POUND } ; [~] => { $ crate :: SyntaxKind :: TILDE } ; [?] => { $ crate :: SyntaxKind :: QUESTION } ; [$] => { $ crate :: SyntaxKind :: DOLLAR } ; [&] => { $ crate :: SyntaxKind :: AMP } ; [|] => { $ crate :: SyntaxKind :: PIPE } ; [+] => { $ crate :: SyntaxKind :: PLUS } ; [*] => { $ crate :: SyntaxKind :: STAR } ; [/] => { $ crate :: SyntaxKind :: SLASH } ; [^] => { $ crate :: SyntaxKind :: CARET } ; [%] => { $ crate :: SyntaxKind :: PERCENT } ; [_] => { $ crate :: SyntaxKind :: UNDERSCORE } ; [.] => { $ crate :: SyntaxKind :: DOT } ; [..] => { $ crate :: SyntaxKind :: DOT2 } ; [...] => { $ crate :: SyntaxKind :: DOT3 } ; [..=] => { $ crate :: SyntaxKind :: DOT2EQ } ; [:] => { $ crate :: SyntaxKind :: COLON } ; [::] => { $ crate :: SyntaxKind :: COLON2 } ; [=] => { $ crate :: SyntaxKind :: EQ } ; [==] => { $ crate :: SyntaxKind :: EQ2 } ; [=>] => { $ crate :: SyntaxKind :: FAT_ARROW } ; [!] => { $ crate :: SyntaxKind :: BANG } ; [!=] => { $ crate :: SyntaxKind :: NEQ } ; [-] => { $ crate :: SyntaxKind :: MINUS } ; [->] => { $ crate :: SyntaxKind :: THIN_ARROW } ; [<=] => { $ crate :: SyntaxKind :: LTEQ } ; [>=] => { $ crate :: SyntaxKind :: GTEQ } ; [+=] => { $ crate :: SyntaxKind :: PLUSEQ } ; [-=] => { $ crate :: SyntaxKind :: MINUSEQ } ; [|=] => { $ crate :: SyntaxKind :: PIPEEQ } ; [&=] => { $ crate :: SyntaxKind :: AMPEQ } ; [^=] => { $ crate :: SyntaxKind :: CARETEQ } ; [/=] => { $ crate :: SyntaxKind :: SLASHEQ } ; [*=] => { $ crate :: SyntaxKind :: STAREQ } ; [%=] => { $ crate :: SyntaxKind :: PERCENTEQ } ; [&&] => { $ crate :: SyntaxKind :: AMP2 } ; [||] => { $ crate :: SyntaxKind :: PIPE2 } ; [<<] => { $ crate :: SyntaxKind :: SHL } ; [>>] => { $ crate :: SyntaxKind :: SHR } ; [<<=] => { $ crate :: SyntaxKind :: SHLEQ } ; [>>=] => { $ crate :: SyntaxKind :: SHREQ } ; [as] => { $ crate :: SyntaxKind :: AS_KW } ; [async] => { $ crate :: SyntaxKind :: ASYNC_KW } ; [await] => { $ crate :: SyntaxKind :: AWAIT_KW } ; [box] => { $ crate :: SyntaxKind :: BOX_KW } ; [break] => { $ crate :: SyntaxKind :: BREAK_KW } ; [const] => { $ crate :: SyntaxKind :: CONST_KW } ; [continue] => { $ crate :: SyntaxKind :: CONTINUE_KW } ; [crate] => { $ crate :: SyntaxKind :: CRATE_KW } ; [do] => { $ crate :: SyntaxKind :: DO_KW } ; [dyn] => { $ crate :: SyntaxKind :: DYN_KW } ; [else] => { $ crate :: SyntaxKind :: ELSE_KW } ; [enum] => { $ crate :: SyntaxKind :: ENUM_KW } ; [extern] => { $ crate :: SyntaxKind :: EXTERN_KW } ; [false] => { $ crate :: SyntaxKind :: FALSE_KW } ; [fn] => { $ crate :: SyntaxKind :: FN_KW } ; [for] => { $ crate :: SyntaxKind :: FOR_KW } ; [if] => { $ crate :: SyntaxKind :: IF_KW } ; [impl] => { $ crate :: SyntaxKind :: IMPL_KW } ; [in] => { $ crate :: SyntaxKind :: IN_KW } ; [let] => { $ crate :: SyntaxKind :: LET_KW } ; [loop] => { $ crate :: SyntaxKind :: LOOP_KW } ; [macro] => { $ crate :: SyntaxKind :: MACRO_KW } ; [match] => { $ crate :: SyntaxKind :: MATCH_KW } ; [mod] => { $ crate :: SyntaxKind :: MOD_KW } ; [move] => { $ crate :: SyntaxKind :: MOVE_KW } ; [mut] => { $ crate :: SyntaxKind :: MUT_KW } ; [pub] => { $ crate :: SyntaxKind :: PUB_KW } ; [ref] => { $ crate :: SyntaxKind :: REF_KW } ; [return] => { $ crate :: SyntaxKind :: RETURN_KW } ; [self] => { $ crate :: SyntaxKind :: SELF_KW } ; [Self] => { $ crate :: SyntaxKind :: SELF_TYPE_KW } ; [static] => { $ crate :: SyntaxKind :: STATIC_KW } ; [struct] => { $ crate :: SyntaxKind :: STRUCT_KW } ; [super] => { $ crate :: SyntaxKind :: SUPER_KW } ; [trait] => { $ crate :: SyntaxKind :: TRAIT_KW } ; [true] => { $ crate :: SyntaxKind :: TRUE_KW } ; [try] => { $ crate :: SyntaxKind :: TRY_KW } ; [type] => { $ crate :: SyntaxKind :: TYPE_KW } ; [unsafe] => { $ crate :: SyntaxKind :: UNSAFE_KW } ; [use] => { $ crate :: SyntaxKind :: USE_KW } ; [where] => { $ crate :: SyntaxKind :: WHERE_KW } ; [while] => { $ crate :: SyntaxKind :: WHILE_KW } ; [yield] => { $ crate :: SyntaxKind :: YIELD_KW } ; [auto] => { $ crate :: SyntaxKind :: AUTO_KW } ; [builtin] => { $ crate :: SyntaxKind :: BUILTIN_KW } ; [default] => { $ crate :: SyntaxKind :: DEFAULT_KW } ; [existential] => { $ crate :: SyntaxKind :: EXISTENTIAL_KW } ; [union] => { $ crate :: SyntaxKind :: UNION_KW } ; [raw] => { $ crate :: SyntaxKind :: RAW_KW } ; [macro_rules] => { $ crate :: SyntaxKind :: MACRO_RULES_KW } ; [yeet] => { $ crate :: SyntaxKind :: YEET_KW } ; [offset_of] => { $ crate :: SyntaxKind :: OFFSET_OF_KW } ; [asm] => { $ crate :: SyntaxKind :: ASM_KW } ; [format_args] => { $ crate :: SyntaxKind :: FORMAT_ARGS_KW } ; [lifetime_ident] => { $ crate :: SyntaxKind :: LIFETIME_IDENT } ; [ident] => { $ crate :: SyntaxKind :: IDENT } ; [shebang] => { $ crate :: SyntaxKind :: SHEBANG } ; } -pub use T; diff --git a/tests/ui/imports/pub-reexport-empty.rs b/tests/ui/imports/pub-reexport-empty.rs new file mode 100644 index 0000000000000..2a46f4c8de86c --- /dev/null +++ b/tests/ui/imports/pub-reexport-empty.rs @@ -0,0 +1,25 @@ +#![deny(unused_imports)] + +mod a {} + +pub use a::*; +//~^ ERROR: unused import: `a::*` + +mod b { + mod c { + #[derive(Clone)] + pub struct D; + } + pub use self::c::*; // don't show unused import lint +} + +pub use b::*; // don't show unused import lint + +mod d { + const D: i32 = 1; +} + +pub use d::*; +//~^ ERROR: unused import: `d::*` + +fn main() {} diff --git a/tests/ui/imports/pub-reexport-empty.stderr b/tests/ui/imports/pub-reexport-empty.stderr new file mode 100644 index 0000000000000..813b2ef71c513 --- /dev/null +++ b/tests/ui/imports/pub-reexport-empty.stderr @@ -0,0 +1,20 @@ +error: unused import: `a::*` + --> $DIR/pub-reexport-empty.rs:5:9 + | +LL | pub use a::*; + | ^^^^ + | +note: the lint level is defined here + --> $DIR/pub-reexport-empty.rs:1:9 + | +LL | #![deny(unused_imports)] + | ^^^^^^^^^^^^^^ + +error: unused import: `d::*` + --> $DIR/pub-reexport-empty.rs:22:9 + | +LL | pub use d::*; + | ^^^^ + +error: aborting due to 2 previous errors + diff --git a/tests/ui/imports/reexports.rs b/tests/ui/imports/reexports.rs index d76cc41be4e55..cb1a3ebe18028 100644 --- a/tests/ui/imports/reexports.rs +++ b/tests/ui/imports/reexports.rs @@ -5,9 +5,12 @@ mod a { mod foo {} mod a { - pub use super::foo; //~ ERROR cannot be re-exported + pub use super::foo; + //~^ ERROR cannot be re-exported + //~| WARNING unused import: `super::foo` pub use super::*; //~^ WARNING glob import doesn't reexport anything because no candidate is public enough + //~| WARNING unused import: `super::*` } } diff --git a/tests/ui/imports/reexports.stderr b/tests/ui/imports/reexports.stderr index 8cbff0ac73dee..401e422af0f8e 100644 --- a/tests/ui/imports/reexports.stderr +++ b/tests/ui/imports/reexports.stderr @@ -11,44 +11,44 @@ LL | pub use super::foo; | ^^^^^^^^^^ error[E0603]: module import `foo` is private - --> $DIR/reexports.rs:33:15 + --> $DIR/reexports.rs:36:15 | LL | use b::a::foo::S; | ^^^ private module import | note: the module import `foo` is defined here... - --> $DIR/reexports.rs:21:17 + --> $DIR/reexports.rs:24:17 | LL | pub use super::foo; // This is OK since the value `foo` is visible enough. | ^^^^^^^^^^ note: ...and refers to the module `foo` which is defined here - --> $DIR/reexports.rs:16:5 + --> $DIR/reexports.rs:19:5 | LL | mod foo { | ^^^^^^^ error[E0603]: module import `foo` is private - --> $DIR/reexports.rs:34:15 + --> $DIR/reexports.rs:37:15 | LL | use b::b::foo::S as T; | ^^^ private module import | note: the module import `foo` is defined here... - --> $DIR/reexports.rs:26:17 + --> $DIR/reexports.rs:29:17 | LL | pub use super::*; // This is also OK since the value `foo` is visible enough. | ^^^^^^^^ note: ...and refers to the module `foo` which is defined here - --> $DIR/reexports.rs:16:5 + --> $DIR/reexports.rs:19:5 | LL | mod foo { | ^^^^^^^ -warning: glob import doesn't reexport anything because no candidate is public enough - --> $DIR/reexports.rs:9:17 +warning: unused import: `super::foo` + --> $DIR/reexports.rs:8:17 | -LL | pub use super::*; - | ^^^^^^^^ +LL | pub use super::foo; + | ^^^^^^^^^^ | note: the lint level is defined here --> $DIR/reexports.rs:1:9 @@ -56,7 +56,19 @@ note: the lint level is defined here LL | #![warn(unused_imports)] | ^^^^^^^^^^^^^^ -error: aborting due to 3 previous errors; 1 warning emitted +warning: glob import doesn't reexport anything because no candidate is public enough + --> $DIR/reexports.rs:11:17 + | +LL | pub use super::*; + | ^^^^^^^^ + +warning: unused import: `super::*` + --> $DIR/reexports.rs:11:17 + | +LL | pub use super::*; + | ^^^^^^^^ + +error: aborting due to 3 previous errors; 3 warnings emitted Some errors have detailed explanations: E0364, E0603. For more information about an error, try `rustc --explain E0364`. diff --git a/tests/ui/lint/unused/lint-unused-imports.rs b/tests/ui/lint/unused/lint-unused-imports.rs index 953992ecf7147..e2a9d3158424f 100644 --- a/tests/ui/lint/unused/lint-unused-imports.rs +++ b/tests/ui/lint/unused/lint-unused-imports.rs @@ -44,7 +44,7 @@ mod foo { mod bar { // Don't ignore on 'pub use' because we're not sure if it's used or not - pub use std::cmp::PartialEq; + pub use std::cmp::PartialEq; //~ ERROR unused import: `std::cmp::PartialEq` pub struct Square; pub mod c { diff --git a/tests/ui/lint/unused/lint-unused-imports.stderr b/tests/ui/lint/unused/lint-unused-imports.stderr index 0574ca4569fbf..0020d57492990 100644 --- a/tests/ui/lint/unused/lint-unused-imports.stderr +++ b/tests/ui/lint/unused/lint-unused-imports.stderr @@ -28,6 +28,12 @@ error: unused import: `bar` LL | use test2::{foo, bar}; | ^^^ +error: unused import: `std::cmp::PartialEq` + --> $DIR/lint-unused-imports.rs:47:13 + | +LL | pub use std::cmp::PartialEq; + | ^^^^^^^^^^^^^^^^^^^ + error: unused import: `foo::Square` --> $DIR/lint-unused-imports.rs:52:13 | @@ -74,5 +80,5 @@ error: unused import: `test::B2` LL | use test::B2; | ^^^^^^^^ -error: aborting due to 10 previous errors +error: aborting due to 11 previous errors diff --git a/tests/ui/parser/recover-missing-semi-before-item.fixed b/tests/ui/parser/recover-missing-semi-before-item.fixed index 0be17e69e8ff7..acb846373cbb2 100644 --- a/tests/ui/parser/recover-missing-semi-before-item.fixed +++ b/tests/ui/parser/recover-missing-semi-before-item.fixed @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_variables, dead_code)] +#![allow(unused_variables, dead_code, unused_imports)] fn for_struct() { let foo = 3; //~ ERROR expected `;`, found keyword `struct` diff --git a/tests/ui/parser/recover-missing-semi-before-item.rs b/tests/ui/parser/recover-missing-semi-before-item.rs index 867b7b749bb1f..ef6cfe3c4ed7a 100644 --- a/tests/ui/parser/recover-missing-semi-before-item.rs +++ b/tests/ui/parser/recover-missing-semi-before-item.rs @@ -1,6 +1,6 @@ // run-rustfix -#![allow(unused_variables, dead_code)] +#![allow(unused_variables, dead_code, unused_imports)] fn for_struct() { let foo = 3 //~ ERROR expected `;`, found keyword `struct` diff --git a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs index 6f115e78e147b..653dcab577148 100644 --- a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs +++ b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.rs @@ -2,13 +2,17 @@ mod rank { pub use self::Professor::*; //~^ ERROR glob import doesn't reexport anything + //~| ERROR unused import: `self::Professor::*` pub use self::Lieutenant::{JuniorGrade, Full}; //~^ ERROR `JuniorGrade` is private, and cannot be re-exported //~| ERROR `Full` is private, and cannot be re-exported + //~| ERROR unused imports: `Full`, `JuniorGrade` pub use self::PettyOfficer::*; //~^ ERROR glob import doesn't reexport anything + //~| ERROR unused import: `self::PettyOfficer::*` pub use self::Crewman::*; //~^ ERROR glob import doesn't reexport anything + //~| ERROR unused import: `self::Crewman::*` enum Professor { Adjunct, diff --git a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr index 59b181fab4001..df5968ba323b3 100644 --- a/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr +++ b/tests/ui/privacy/issue-46209-private-enum-variant-reexport.stderr @@ -1,23 +1,23 @@ error[E0364]: `JuniorGrade` is private, and cannot be re-exported - --> $DIR/issue-46209-private-enum-variant-reexport.rs:5:32 + --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:32 | LL | pub use self::Lieutenant::{JuniorGrade, Full}; | ^^^^^^^^^^^ | note: consider marking `JuniorGrade` as `pub` in the imported module - --> $DIR/issue-46209-private-enum-variant-reexport.rs:5:32 + --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:32 | LL | pub use self::Lieutenant::{JuniorGrade, Full}; | ^^^^^^^^^^^ error[E0364]: `Full` is private, and cannot be re-exported - --> $DIR/issue-46209-private-enum-variant-reexport.rs:5:45 + --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:45 | LL | pub use self::Lieutenant::{JuniorGrade, Full}; | ^^^^ | note: consider marking `Full` as `pub` in the imported module - --> $DIR/issue-46209-private-enum-variant-reexport.rs:5:45 + --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:45 | LL | pub use self::Lieutenant::{JuniorGrade, Full}; | ^^^^ @@ -34,18 +34,42 @@ note: the lint level is defined here LL | #[deny(unused_imports)] | ^^^^^^^^^^^^^^ +error: unused import: `self::Professor::*` + --> $DIR/issue-46209-private-enum-variant-reexport.rs:3:13 + | +LL | pub use self::Professor::*; + | ^^^^^^^^^^^^^^^^^^ + +error: unused imports: `Full`, `JuniorGrade` + --> $DIR/issue-46209-private-enum-variant-reexport.rs:6:32 + | +LL | pub use self::Lieutenant::{JuniorGrade, Full}; + | ^^^^^^^^^^^ ^^^^ + error: glob import doesn't reexport anything because no candidate is public enough - --> $DIR/issue-46209-private-enum-variant-reexport.rs:8:13 + --> $DIR/issue-46209-private-enum-variant-reexport.rs:10:13 | LL | pub use self::PettyOfficer::*; | ^^^^^^^^^^^^^^^^^^^^^ -error: glob import doesn't reexport anything because no candidate is public enough +error: unused import: `self::PettyOfficer::*` --> $DIR/issue-46209-private-enum-variant-reexport.rs:10:13 | +LL | pub use self::PettyOfficer::*; + | ^^^^^^^^^^^^^^^^^^^^^ + +error: glob import doesn't reexport anything because no candidate is public enough + --> $DIR/issue-46209-private-enum-variant-reexport.rs:13:13 + | +LL | pub use self::Crewman::*; + | ^^^^^^^^^^^^^^^^ + +error: unused import: `self::Crewman::*` + --> $DIR/issue-46209-private-enum-variant-reexport.rs:13:13 + | LL | pub use self::Crewman::*; | ^^^^^^^^^^^^^^^^ -error: aborting due to 5 previous errors +error: aborting due to 9 previous errors For more information about this error, try `rustc --explain E0364`. diff --git a/tests/ui/privacy/private-variant-reexport.rs b/tests/ui/privacy/private-variant-reexport.rs index 6882844602286..b59243af62067 100644 --- a/tests/ui/privacy/private-variant-reexport.rs +++ b/tests/ui/privacy/private-variant-reexport.rs @@ -12,7 +12,9 @@ mod m3 { #[deny(unused_imports)] mod m4 { - pub use ::E::*; //~ ERROR glob import doesn't reexport anything + pub use ::E::*; + //~^ ERROR glob import doesn't reexport anything + //~| ERROR unused import: `::E::*` } enum E { V } diff --git a/tests/ui/privacy/private-variant-reexport.stderr b/tests/ui/privacy/private-variant-reexport.stderr index 78771ee30d314..2f041934a8171 100644 --- a/tests/ui/privacy/private-variant-reexport.stderr +++ b/tests/ui/privacy/private-variant-reexport.stderr @@ -42,7 +42,13 @@ note: the lint level is defined here LL | #[deny(unused_imports)] | ^^^^^^^^^^^^^^ -error: aborting due to 4 previous errors +error: unused import: `::E::*` + --> $DIR/private-variant-reexport.rs:15:13 + | +LL | pub use ::E::*; + | ^^^^^^ + +error: aborting due to 5 previous errors Some errors have detailed explanations: E0364, E0365. For more information about an error, try `rustc --explain E0364`. From fdaff054a12f8fc0783646a1cc3d17d6a5b1d1d7 Mon Sep 17 00:00:00 2001 From: bohan Date: Thu, 12 Oct 2023 22:13:38 +0800 Subject: [PATCH 51/52] delete useless pub detect during check unused --- compiler/rustc_resolve/src/check_unused.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/compiler/rustc_resolve/src/check_unused.rs b/compiler/rustc_resolve/src/check_unused.rs index baa7d87039954..352bf98d01fb2 100644 --- a/compiler/rustc_resolve/src/check_unused.rs +++ b/compiler/rustc_resolve/src/check_unused.rs @@ -59,7 +59,6 @@ struct UnusedImportCheckVisitor<'a, 'b, 'tcx> { base_use_tree: Option<&'a ast::UseTree>, base_id: ast::NodeId, item_span: Span, - base_use_is_pub: bool, } struct ExternCrateToLint { @@ -146,7 +145,6 @@ impl<'a, 'b, 'tcx> Visitor<'a> for UnusedImportCheckVisitor<'a, 'b, 'tcx> { // because this means that they were generated in some fashion by the // compiler and we don't need to consider them. ast::ItemKind::Use(..) if item.span.is_dummy() => return, - ast::ItemKind::Use(..) => self.base_use_is_pub = item.vis.kind.is_pub(), ast::ItemKind::ExternCrate(orig_name) => { self.extern_crate_items.push(ExternCrateToLint { id: item.id, @@ -332,7 +330,6 @@ impl Resolver<'_, '_> { base_use_tree: None, base_id: ast::DUMMY_NODE_ID, item_span: DUMMY_SP, - base_use_is_pub: false, }; visit::walk_crate(&mut visitor, krate); From 1703f14ddaf98200d5e4664675409b56a17e7666 Mon Sep 17 00:00:00 2001 From: bohan Date: Fri, 13 Oct 2023 12:58:57 +0800 Subject: [PATCH 52/52] delete more useless pub --- library/core/tests/lib.rs | 2 -- library/core/tests/num/flt2dec/mod.rs | 2 -- library/std/src/sys/common/mod.rs | 1 + src/tools/clippy/tests/ui/enum_glob_use.fixed | 2 +- src/tools/clippy/tests/ui/enum_glob_use.stderr | 11 ++++++++++- src/tools/miri/tests/utils/mod.rs | 1 + .../crates/syntax/src/tests/sourcegen_ast.rs | 1 - src/tools/rustfmt/src/config/options.rs | 7 ------- 8 files changed, 13 insertions(+), 14 deletions(-) diff --git a/library/core/tests/lib.rs b/library/core/tests/lib.rs index 1a01efa5ba95a..3e743d2371dbb 100644 --- a/library/core/tests/lib.rs +++ b/library/core/tests/lib.rs @@ -121,8 +121,6 @@ #![deny(unsafe_op_in_unsafe_fn)] #![deny(fuzzy_provenance_casts)] -extern crate test; - mod alloc; mod any; mod array; diff --git a/library/core/tests/num/flt2dec/mod.rs b/library/core/tests/num/flt2dec/mod.rs index 30843cc3dd79c..83e2707b57e8b 100644 --- a/library/core/tests/num/flt2dec/mod.rs +++ b/library/core/tests/num/flt2dec/mod.rs @@ -8,8 +8,6 @@ use core::num::flt2dec::{ }; use core::num::fmt::{Formatted, Part}; -pub use test::Bencher; - mod estimator; mod strategy { mod dragon; diff --git a/library/std/src/sys/common/mod.rs b/library/std/src/sys/common/mod.rs index 2b8782ddf4482..c7721a1f9a792 100644 --- a/library/std/src/sys/common/mod.rs +++ b/library/std/src/sys/common/mod.rs @@ -9,6 +9,7 @@ // Progress on this is tracked in #84187. #![allow(dead_code)] +#![allow(unused_imports)] pub mod alloc; pub mod small_c_string; diff --git a/src/tools/clippy/tests/ui/enum_glob_use.fixed b/src/tools/clippy/tests/ui/enum_glob_use.fixed index 9044e80268dbf..7b346eefb4553 100644 --- a/src/tools/clippy/tests/ui/enum_glob_use.fixed +++ b/src/tools/clippy/tests/ui/enum_glob_use.fixed @@ -19,7 +19,7 @@ mod in_fn_test { } mod blurg { - pub use std::cmp::Ordering::*; // ok, re-export + // ok, re-export } fn main() { diff --git a/src/tools/clippy/tests/ui/enum_glob_use.stderr b/src/tools/clippy/tests/ui/enum_glob_use.stderr index 8b94e67f87ea3..73a051afa824b 100644 --- a/src/tools/clippy/tests/ui/enum_glob_use.stderr +++ b/src/tools/clippy/tests/ui/enum_glob_use.stderr @@ -1,3 +1,12 @@ +error: unused import: `std::cmp::Ordering::*` + --> $DIR/enum_glob_use.rs:22:13 + | +LL | pub use std::cmp::Ordering::*; // ok, re-export + | ^^^^^^^^^^^^^^^^^^^^^ + | + = note: `-D unused-imports` implied by `-D warnings` + = help: to override `-D warnings` add `#[allow(unused_imports)]` + error: usage of wildcard import for enum variants --> $DIR/enum_glob_use.rs:5:5 | @@ -19,5 +28,5 @@ error: usage of wildcard import for enum variants LL | use crate::Enum::*; | ^^^^^^^^^^^^^^ help: try: `crate::Enum::Foo` -error: aborting due to 3 previous errors +error: aborting due to 4 previous errors diff --git a/src/tools/miri/tests/utils/mod.rs b/src/tools/miri/tests/utils/mod.rs index 593f82910c6fe..7b7dc231a5019 100644 --- a/src/tools/miri/tests/utils/mod.rs +++ b/src/tools/miri/tests/utils/mod.rs @@ -1,4 +1,5 @@ #![allow(dead_code)] +#![allow(unused_imports)] #[macro_use] mod macros; diff --git a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs index 56227fce9b5c5..dc6c96343d61c 100644 --- a/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs +++ b/src/tools/rust-analyzer/crates/syntax/src/tests/sourcegen_ast.rs @@ -450,7 +450,6 @@ fn generate_syntax_kinds(grammar: KindsSrc<'_>) -> String { [ident] => { $crate::SyntaxKind::IDENT }; [shebang] => { $crate::SyntaxKind::SHEBANG }; } - pub use T; }; sourcegen::add_preamble("sourcegen_ast", sourcegen::reformat(ast.to_string())) diff --git a/src/tools/rustfmt/src/config/options.rs b/src/tools/rustfmt/src/config/options.rs index 3aa1a4de99d66..651453aa422ee 100644 --- a/src/tools/rustfmt/src/config/options.rs +++ b/src/tools/rustfmt/src/config/options.rs @@ -142,13 +142,6 @@ pub enum HexLiteralCase { Lower, } -#[config_type] -pub enum ReportTactic { - Always, - Unnumbered, - Never, -} - /// What Rustfmt should emit. Mostly corresponds to the `--emit` command line /// option. #[config_type]