diff --git a/compiler/rustc_arena/src/lib.rs b/compiler/rustc_arena/src/lib.rs index 6f9ecb9cd21e0..3928d70c0ede2 100644 --- a/compiler/rustc_arena/src/lib.rs +++ b/compiler/rustc_arena/src/lib.rs @@ -45,24 +45,24 @@ pub struct TypedArena { end: Cell<*mut T>, /// A vector of arena chunks. - chunks: RefCell>>, + chunks: RefCell>>, /// Marker indicating that dropping the arena causes its owned /// instances of `T` to be dropped. _own: PhantomData, } -struct TypedArenaChunk { +struct ArenaChunk { /// The raw storage for the arena chunk. storage: Box<[MaybeUninit]>, /// The number of valid entries in the chunk. entries: usize, } -impl TypedArenaChunk { +impl ArenaChunk { #[inline] - unsafe fn new(capacity: usize) -> TypedArenaChunk { - TypedArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 } + unsafe fn new(capacity: usize) -> ArenaChunk { + ArenaChunk { storage: Box::new_uninit_slice(capacity), entries: 0 } } /// Destroys this arena chunk. @@ -125,6 +125,11 @@ impl IterExt for I where I: IntoIterator, { + // This default collects into a `SmallVec` and then allocates by copying + // from it. The specializations below for types like `Vec` are more + // efficient, copying directly without the intermediate collecting step. + // This default could be made more efficient, like + // `DroplessArena::alloc_from_iter`, but it's not hot enough to bother. #[inline] default fn alloc_from_iter(self, arena: &TypedArena) -> &mut [T] { let vec: SmallVec<[_; 8]> = self.into_iter().collect(); @@ -139,7 +144,7 @@ impl IterExt for std::array::IntoIter { if len == 0 { return &mut []; } - // Move the content to the arena by copying and then forgetting it + // Move the content to the arena by copying and then forgetting it. unsafe { let start_ptr = arena.alloc_raw_slice(len); self.as_slice().as_ptr().copy_to_nonoverlapping(start_ptr, len); @@ -156,7 +161,7 @@ impl IterExt for Vec { if len == 0 { return &mut []; } - // Move the content to the arena by copying and then forgetting it + // Move the content to the arena by copying and then forgetting it. unsafe { let start_ptr = arena.alloc_raw_slice(len); self.as_ptr().copy_to_nonoverlapping(start_ptr, len); @@ -173,7 +178,7 @@ impl IterExt for SmallVec { if len == 0 { return &mut []; } - // Move the content to the arena by copying and then forgetting it + // Move the content to the arena by copying and then forgetting it. unsafe { let start_ptr = arena.alloc_raw_slice(len); self.as_ptr().copy_to_nonoverlapping(start_ptr, len); @@ -272,7 +277,7 @@ impl TypedArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let mut chunk = TypedArenaChunk::::new(new_cap); + let mut chunk = ArenaChunk::::new(new_cap); self.ptr.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); @@ -281,7 +286,7 @@ impl TypedArena { // Drops the contents of the last chunk. The last chunk is partially empty, unlike all other // chunks. - fn clear_last_chunk(&self, last_chunk: &mut TypedArenaChunk) { + fn clear_last_chunk(&self, last_chunk: &mut ArenaChunk) { // Determine how much was filled. let start = last_chunk.start() as usize; // We obtain the value of the pointer to the first uninitialized element. @@ -340,7 +345,7 @@ pub struct DroplessArena { end: Cell<*mut u8>, /// A vector of arena chunks. - chunks: RefCell>>, + chunks: RefCell>, } unsafe impl Send for DroplessArena {} @@ -378,7 +383,7 @@ impl DroplessArena { // Also ensure that this chunk can fit `additional`. new_cap = cmp::max(additional, new_cap); - let mut chunk = TypedArenaChunk::::new(new_cap); + let mut chunk = ArenaChunk::new(new_cap); self.start.set(chunk.start()); self.end.set(chunk.end()); chunks.push(chunk); @@ -520,10 +525,19 @@ impl DroplessArena { } } -// Declare an `Arena` containing one dropless arena and many typed arenas (the -// types of the typed arenas are specified by the arguments). The dropless -// arena will be used for any types that impl `Copy`, and also for any of the -// specified types that satisfy `!mem::needs_drop`. +/// Declare an `Arena` containing one dropless arena and many typed arenas (the +/// types of the typed arenas are specified by the arguments). +/// +/// There are three cases of interest. +/// - Types that are `Copy`: these need not be specified in the arguments. They +/// will use the `DroplessArena`. +/// - Types that are `!Copy` and `!Drop`: these must be specified in the +/// arguments. An empty `TypedArena` will be created for each one, but the +/// `DroplessArena` will always be used and the `TypedArena` will stay empty. +/// This is odd but harmless, because an empty arena allocates no memory. +/// - Types that are `!Copy` and `Drop`: these must be specified in the +/// arguments. The `TypedArena` will be used for them. +/// #[rustc_macro_transparency = "semitransparent"] pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { #[derive(Default)] @@ -532,7 +546,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { $($name: $crate::TypedArena<$ty>,)* } - pub trait ArenaAllocatable<'tcx, T = Self>: Sized { + pub trait ArenaAllocatable<'tcx, C = rustc_arena::IsNotCopy>: Sized { fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self; fn allocate_from_iter<'a>( arena: &'a Arena<'tcx>, @@ -541,7 +555,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { } // Any type that impls `Copy` can be arena-allocated in the `DroplessArena`. - impl<'tcx, T: Copy> ArenaAllocatable<'tcx, ()> for T { + impl<'tcx, T: Copy> ArenaAllocatable<'tcx, rustc_arena::IsCopy> for T { #[inline] fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { arena.dropless.alloc(self) @@ -555,7 +569,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { } } $( - impl<'tcx> ArenaAllocatable<'tcx, $ty> for $ty { + impl<'tcx> ArenaAllocatable<'tcx, rustc_arena::IsNotCopy> for $ty { #[inline] fn allocate_on<'a>(self, arena: &'a Arena<'tcx>) -> &'a mut Self { if !::std::mem::needs_drop::() { @@ -581,7 +595,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { impl<'tcx> Arena<'tcx> { #[inline] - pub fn alloc, U>(&self, value: T) -> &mut T { + pub fn alloc, C>(&self, value: T) -> &mut T { value.allocate_on(self) } @@ -594,7 +608,7 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { self.dropless.alloc_slice(value) } - pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, U>, U>( + pub fn alloc_from_iter<'a, T: ArenaAllocatable<'tcx, C>, C>( &'a self, iter: impl ::std::iter::IntoIterator, ) -> &'a mut [T] { @@ -603,5 +617,10 @@ pub macro declare_arena([$($a:tt $name:ident: $ty:ty,)*]) { } } +// Marker types that let us give different behaviour for arenas allocating +// `Copy` types vs `!Copy` types. +pub struct IsCopy; +pub struct IsNotCopy; + #[cfg(test)] mod tests; diff --git a/compiler/rustc_ast_pretty/src/pprust/state.rs b/compiler/rustc_ast_pretty/src/pprust/state.rs index 1cbc3162d4326..96dbd3dca156e 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state.rs @@ -607,7 +607,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere &mut self, macro_def: &ast::MacroDef, ident: &Ident, - sp: &Span, + sp: Span, print_visibility: impl FnOnce(&mut Self), ) { let (kw, has_bang) = if macro_def.macro_rules { @@ -623,7 +623,7 @@ pub trait PrintState<'a>: std::ops::Deref + std::ops::Dere macro_def.body.delim(), ¯o_def.body.inner_tokens(), true, - *sp, + sp, ); if macro_def.body.need_semicolon() { self.word(";"); diff --git a/compiler/rustc_ast_pretty/src/pprust/state/item.rs b/compiler/rustc_ast_pretty/src/pprust/state/item.rs index c756b946b1e4a..e575d6aa7e2fc 100644 --- a/compiler/rustc_ast_pretty/src/pprust/state/item.rs +++ b/compiler/rustc_ast_pretty/src/pprust/state/item.rs @@ -347,7 +347,7 @@ impl<'a> State<'a> { } } ast::ItemKind::MacroDef(ref macro_def) => { - self.print_mac_def(macro_def, &item.ident, &item.span, |state| { + self.print_mac_def(macro_def, &item.ident, item.span, |state| { state.print_visibility(&item.vis) }); } diff --git a/compiler/rustc_data_structures/src/stable_hasher/tests.rs b/compiler/rustc_data_structures/src/stable_hasher/tests.rs index 391db67d29dbb..31190363eb61b 100644 --- a/compiler/rustc_data_structures/src/stable_hasher/tests.rs +++ b/compiler/rustc_data_structures/src/stable_hasher/tests.rs @@ -98,3 +98,45 @@ fn test_hash_bit_matrix() { assert_ne!(a, b); assert_ne!(hash(&a), hash(&b)); } + +// Check that exchanging the value of two adjacent fields changes the hash. +#[test] +fn test_attribute_permutation() { + macro_rules! test_type { + ($ty: ty) => {{ + struct Foo { + a: $ty, + b: $ty, + } + + impl HashStable for Foo { + fn hash_stable(&self, hcx: &mut CTX, hasher: &mut StableHasher) { + self.a.hash_stable(hcx, hasher); + self.b.hash_stable(hcx, hasher); + } + } + + #[allow(overflowing_literals)] + let mut item = Foo { a: 0xFF, b: 0xFF_FF }; + let hash_a = hash(&item); + std::mem::swap(&mut item.a, &mut item.b); + let hash_b = hash(&item); + assert_ne!( + hash_a, + hash_b, + "The hash stayed the same after values were swapped for type `{}`!", + stringify!($ty) + ); + }}; + } + + test_type!(u16); + test_type!(u32); + test_type!(u64); + test_type!(u128); + + test_type!(i16); + test_type!(i32); + test_type!(i64); + test_type!(i128); +} diff --git a/compiler/rustc_feature/src/builtin_attrs.rs b/compiler/rustc_feature/src/builtin_attrs.rs index 0e643ff599834..fc7f01f041d34 100644 --- a/compiler/rustc_feature/src/builtin_attrs.rs +++ b/compiler/rustc_feature/src/builtin_attrs.rs @@ -625,7 +625,7 @@ pub const BUILTIN_ATTRIBUTES: &[BuiltinAttribute] = &[ ), rustc_attr!( rustc_pass_by_value, Normal, - template!(Word), WarnFollowing, + template!(Word), ErrorFollowing, "#[rustc_pass_by_value] is used to mark types that must be passed by value instead of reference." ), BuiltinAttribute { diff --git a/compiler/rustc_hir_pretty/src/lib.rs b/compiler/rustc_hir_pretty/src/lib.rs index 9e54122f8dd5c..a47ebaf1237a1 100644 --- a/compiler/rustc_hir_pretty/src/lib.rs +++ b/compiler/rustc_hir_pretty/src/lib.rs @@ -571,7 +571,7 @@ impl<'a> State<'a> { self.ann.nested(self, Nested::Body(body)); } hir::ItemKind::Macro(ref macro_def) => { - self.print_mac_def(macro_def, &item.ident, &item.span, |state| { + self.print_mac_def(macro_def, &item.ident, item.span, |state| { state.print_visibility(&item.vis) }); } diff --git a/compiler/rustc_lint/src/internal.rs b/compiler/rustc_lint/src/internal.rs index 7353cd6b876b9..d8e1162890c60 100644 --- a/compiler/rustc_lint/src/internal.rs +++ b/compiler/rustc_lint/src/internal.rs @@ -108,7 +108,7 @@ impl<'tcx> LateLintPass<'tcx> for TyTyKind { lint.build(&format!("usage of qualified `ty::{}`", t)) .span_suggestion( path.span, - "try using it unqualified", + "try importing it and using it unqualified", t, // The import probably needs to be changed Applicability::MaybeIncorrect, diff --git a/compiler/rustc_lint/src/non_fmt_panic.rs b/compiler/rustc_lint/src/non_fmt_panic.rs index a919b3c82aa02..6bf25732f6035 100644 --- a/compiler/rustc_lint/src/non_fmt_panic.rs +++ b/compiler/rustc_lint/src/non_fmt_panic.rs @@ -336,5 +336,5 @@ fn is_arg_inside_call(arg: Span, call: Span) -> bool { // panic call in the source file, to avoid invalid suggestions when macros are involved. // We specifically check for the spans to not be identical, as that happens sometimes when // proc_macros lie about spans and apply the same span to all the tokens they produce. - call.contains(arg) && !call.source_equal(&arg) + call.contains(arg) && !call.source_equal(arg) } diff --git a/compiler/rustc_lint/src/pass_by_value.rs b/compiler/rustc_lint/src/pass_by_value.rs index 26d0560bf89bb..2caf929788f18 100644 --- a/compiler/rustc_lint/src/pass_by_value.rs +++ b/compiler/rustc_lint/src/pass_by_value.rs @@ -76,10 +76,10 @@ fn gen_args(cx: &LateContext<'_>, segment: &PathSegment<'_>) -> String { .map(|arg| match arg { GenericArg::Lifetime(lt) => lt.name.ident().to_string(), GenericArg::Type(ty) => { - cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_default() + cx.tcx.sess.source_map().span_to_snippet(ty.span).unwrap_or_else(|_| "_".into()) } GenericArg::Const(c) => { - cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_default() + cx.tcx.sess.source_map().span_to_snippet(c.span).unwrap_or_else(|_| "_".into()) } GenericArg::Infer(_) => String::from("_"), }) diff --git a/compiler/rustc_middle/src/mir/spanview.rs b/compiler/rustc_middle/src/mir/spanview.rs index 06cbc3383efff..965d30a7b92c9 100644 --- a/compiler/rustc_middle/src/mir/spanview.rs +++ b/compiler/rustc_middle/src/mir/spanview.rs @@ -230,7 +230,7 @@ where } /// Format a string showing the start line and column, and end line and column within a file. -pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: &Span) -> String { +pub fn source_range_no_file<'tcx>(tcx: TyCtxt<'tcx>, span: Span) -> String { let source_map = tcx.sess.source_map(); let start = source_map.lookup_char_pos(span.lo()); let end = source_map.lookup_char_pos(span.hi()); @@ -629,7 +629,7 @@ fn tooltip<'tcx>( let mut text = Vec::new(); text.push(format!("{}: {}:", spanview_id, &source_map.span_to_embeddable_string(span))); for statement in statements { - let source_range = source_range_no_file(tcx, &statement.source_info.span); + let source_range = source_range_no_file(tcx, statement.source_info.span); text.push(format!( "\n{}{}: {}: {:?}", TOOLTIP_INDENT, @@ -639,7 +639,7 @@ fn tooltip<'tcx>( )); } if let Some(term) = terminator { - let source_range = source_range_no_file(tcx, &term.source_info.span); + let source_range = source_range_no_file(tcx, term.source_info.span); text.push(format!( "\n{}{}: {}: {:?}", TOOLTIP_INDENT, diff --git a/compiler/rustc_mir_transform/src/coverage/spans.rs b/compiler/rustc_mir_transform/src/coverage/spans.rs index 237cb1e11053a..d1cb2826dedfc 100644 --- a/compiler/rustc_mir_transform/src/coverage/spans.rs +++ b/compiler/rustc_mir_transform/src/coverage/spans.rs @@ -28,7 +28,7 @@ impl CoverageStatement { let stmt = &mir_body[bb].statements[stmt_index]; format!( "{}: @{}[{}]: {:?}", - source_range_no_file(tcx, &span), + source_range_no_file(tcx, span), bb.index(), stmt_index, stmt @@ -38,7 +38,7 @@ impl CoverageStatement { let term = mir_body[bb].terminator(); format!( "{}: @{}.{}: {:?}", - source_range_no_file(tcx, &span), + source_range_no_file(tcx, span), bb.index(), term_type(&term.kind), term.kind @@ -155,7 +155,7 @@ impl CoverageSpan { pub fn format<'tcx>(&self, tcx: TyCtxt<'tcx>, mir_body: &mir::Body<'tcx>) -> String { format!( "{}\n {}", - source_range_no_file(tcx, &self.span), + source_range_no_file(tcx, self.span), self.format_coverage_statements(tcx, mir_body).replace('\n', "\n "), ) } diff --git a/compiler/rustc_parse/src/parser/item.rs b/compiler/rustc_parse/src/parser/item.rs index ade441b0e7d5c..06849b3125683 100644 --- a/compiler/rustc_parse/src/parser/item.rs +++ b/compiler/rustc_parse/src/parser/item.rs @@ -423,7 +423,7 @@ impl<'a> Parser<'a> { // Maybe the user misspelled `macro_rules` (issue #91227) if self.token.is_ident() && path.segments.len() == 1 - && lev_distance("macro_rules", &path.segments[0].ident.to_string()) <= 3 + && lev_distance("macro_rules", &path.segments[0].ident.to_string(), 3).is_some() { err.span_suggestion( path.span, diff --git a/compiler/rustc_span/src/lev_distance.rs b/compiler/rustc_span/src/lev_distance.rs index aed699e4839e9..93cf965f1056b 100644 --- a/compiler/rustc_span/src/lev_distance.rs +++ b/compiler/rustc_span/src/lev_distance.rs @@ -11,16 +11,21 @@ use std::cmp; mod tests; /// Finds the Levenshtein distance between two strings. -pub fn lev_distance(a: &str, b: &str) -> usize { - // cases which don't require further computation - if a.is_empty() { - return b.chars().count(); - } else if b.is_empty() { - return a.chars().count(); +/// +/// Returns None if the distance exceeds the limit. +pub fn lev_distance(a: &str, b: &str, limit: usize) -> Option { + let n = a.chars().count(); + let m = b.chars().count(); + let min_dist = if n < m { m - n } else { n - m }; + + if min_dist > limit { + return None; + } + if n == 0 || m == 0 { + return (min_dist <= limit).then_some(min_dist); } - let mut dcol: Vec<_> = (0..=b.len()).collect(); - let mut t_last = 0; + let mut dcol: Vec<_> = (0..=m).collect(); for (i, sc) in a.chars().enumerate() { let mut current = i; @@ -35,10 +40,10 @@ pub fn lev_distance(a: &str, b: &str) -> usize { dcol[j + 1] = cmp::min(dcol[j + 1], dcol[j]) + 1; } current = next; - t_last = j; } } - dcol[t_last + 1] + + (dcol[m] <= limit).then_some(dcol[m]) } /// Finds the best match for a given word in the given iterator. @@ -51,39 +56,38 @@ pub fn lev_distance(a: &str, b: &str) -> usize { /// on an edge case with a lower(upper)case letters mismatch. #[cold] pub fn find_best_match_for_name( - name_vec: &[Symbol], + candidates: &[Symbol], lookup: Symbol, dist: Option, ) -> Option { let lookup = lookup.as_str(); - let max_dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); + let lookup_uppercase = lookup.to_uppercase(); // Priority of matches: // 1. Exact case insensitive match // 2. Levenshtein distance match // 3. Sorted word match - if let Some(case_insensitive_match) = - name_vec.iter().find(|candidate| candidate.as_str().to_uppercase() == lookup.to_uppercase()) - { - return Some(*case_insensitive_match); + if let Some(c) = candidates.iter().find(|c| c.as_str().to_uppercase() == lookup_uppercase) { + return Some(*c); } - let levenshtein_match = name_vec - .iter() - .filter_map(|&name| { - let dist = lev_distance(lookup, name.as_str()); - if dist <= max_dist { Some((name, dist)) } else { None } - }) - // Here we are collecting the next structure: - // (levenshtein_match, levenshtein_distance) - .fold(None, |result, (candidate, dist)| match result { - None => Some((candidate, dist)), - Some((c, d)) => Some(if dist < d { (candidate, dist) } else { (c, d) }), - }); - if levenshtein_match.is_some() { - levenshtein_match.map(|(candidate, _)| candidate) - } else { - find_match_by_sorted_words(name_vec, lookup) + + let mut dist = dist.unwrap_or_else(|| cmp::max(lookup.len(), 3) / 3); + let mut best = None; + for c in candidates { + match lev_distance(lookup, c.as_str(), dist) { + Some(0) => return Some(*c), + Some(d) => { + dist = d - 1; + best = Some(*c); + } + None => {} + } } + if best.is_some() { + return best; + } + + find_match_by_sorted_words(candidates, lookup) } fn find_match_by_sorted_words(iter_names: &[Symbol], lookup: &str) -> Option { diff --git a/compiler/rustc_span/src/lev_distance/tests.rs b/compiler/rustc_span/src/lev_distance/tests.rs index b32f8d32c1391..4e34219248d41 100644 --- a/compiler/rustc_span/src/lev_distance/tests.rs +++ b/compiler/rustc_span/src/lev_distance/tests.rs @@ -5,18 +5,26 @@ fn test_lev_distance() { use std::char::{from_u32, MAX}; // Test bytelength agnosticity for c in (0..MAX as u32).filter_map(from_u32).map(|i| i.to_string()) { - assert_eq!(lev_distance(&c[..], &c[..]), 0); + assert_eq!(lev_distance(&c[..], &c[..], usize::MAX), Some(0)); } let a = "\nMäry häd ä little lämb\n\nLittle lämb\n"; let b = "\nMary häd ä little lämb\n\nLittle lämb\n"; let c = "Mary häd ä little lämb\n\nLittle lämb\n"; - assert_eq!(lev_distance(a, b), 1); - assert_eq!(lev_distance(b, a), 1); - assert_eq!(lev_distance(a, c), 2); - assert_eq!(lev_distance(c, a), 2); - assert_eq!(lev_distance(b, c), 1); - assert_eq!(lev_distance(c, b), 1); + assert_eq!(lev_distance(a, b, usize::MAX), Some(1)); + assert_eq!(lev_distance(b, a, usize::MAX), Some(1)); + assert_eq!(lev_distance(a, c, usize::MAX), Some(2)); + assert_eq!(lev_distance(c, a, usize::MAX), Some(2)); + assert_eq!(lev_distance(b, c, usize::MAX), Some(1)); + assert_eq!(lev_distance(c, b, usize::MAX), Some(1)); +} + +#[test] +fn test_lev_distance_limit() { + assert_eq!(lev_distance("abc", "abcd", 1), Some(1)); + assert_eq!(lev_distance("abc", "abcd", 0), None); + assert_eq!(lev_distance("abc", "xyz", 3), Some(3)); + assert_eq!(lev_distance("abc", "xyz", 2), None); } #[test] diff --git a/compiler/rustc_span/src/lib.rs b/compiler/rustc_span/src/lib.rs index 92360164a019b..2c3db35bb66cb 100644 --- a/compiler/rustc_span/src/lib.rs +++ b/compiler/rustc_span/src/lib.rs @@ -15,6 +15,7 @@ #![doc(html_root_url = "https://doc.rust-lang.org/nightly/nightly-rustc/")] #![feature(array_windows)] +#![feature(bool_to_option)] #![feature(crate_visibility_modifier)] #![feature(if_let_guard)] #![feature(negative_impls)] @@ -611,7 +612,7 @@ impl Span { #[inline] /// Returns `true` if `hi == lo`. - pub fn is_empty(&self) -> bool { + pub fn is_empty(self) -> bool { let span = self.data_untracked(); span.hi == span.lo } @@ -639,7 +640,7 @@ impl Span { /// /// Use this instead of `==` when either span could be generated code, /// and you only care that they point to the same bytes of source text. - pub fn source_equal(&self, other: &Span) -> bool { + pub fn source_equal(self, other: Span) -> bool { let span = self.data(); let other = other.data(); span.lo == other.lo && span.hi == other.hi @@ -680,17 +681,17 @@ impl Span { } #[inline] - pub fn rust_2015(&self) -> bool { + pub fn rust_2015(self) -> bool { self.edition() == edition::Edition::Edition2015 } #[inline] - pub fn rust_2018(&self) -> bool { + pub fn rust_2018(self) -> bool { self.edition() >= edition::Edition::Edition2018 } #[inline] - pub fn rust_2021(&self) -> bool { + pub fn rust_2021(self) -> bool { self.edition() >= edition::Edition::Edition2021 } @@ -711,7 +712,7 @@ impl Span { /// Checks if a span is "internal" to a macro in which `#[unstable]` /// items can be used (that is, a macro marked with /// `#[allow_internal_unstable]`). - pub fn allows_unstable(&self, feature: Symbol) -> bool { + pub fn allows_unstable(self, feature: Symbol) -> bool { self.ctxt() .outer_expn_data() .allow_internal_unstable @@ -719,7 +720,7 @@ impl Span { } /// Checks if this span arises from a compiler desugaring of kind `kind`. - pub fn is_desugaring(&self, kind: DesugaringKind) -> bool { + pub fn is_desugaring(self, kind: DesugaringKind) -> bool { match self.ctxt().outer_expn_data().kind { ExpnKind::Desugaring(k) => k == kind, _ => false, @@ -728,7 +729,7 @@ impl Span { /// Returns the compiler desugaring that created this span, or `None` /// if this span is not from a desugaring. - pub fn desugaring_kind(&self) -> Option { + pub fn desugaring_kind(self) -> Option { match self.ctxt().outer_expn_data().kind { ExpnKind::Desugaring(k) => Some(k), _ => None, @@ -738,7 +739,7 @@ impl Span { /// Checks if a span is "internal" to a macro in which `unsafe` /// can be used without triggering the `unsafe_code` lint. // (that is, a macro marked with `#[allow_internal_unsafe]`). - pub fn allows_unsafe(&self) -> bool { + pub fn allows_unsafe(self) -> bool { self.ctxt().outer_expn_data().allow_internal_unsafe } @@ -751,7 +752,7 @@ impl Span { return None; } - let is_recursive = expn_data.call_site.source_equal(&prev_span); + let is_recursive = expn_data.call_site.source_equal(prev_span); prev_span = self; self = expn_data.call_site; @@ -865,13 +866,13 @@ impl Span { /// Equivalent of `Span::call_site` from the proc macro API, /// except that the location is taken from the `self` span. - pub fn with_call_site_ctxt(&self, expn_id: ExpnId) -> Span { + pub fn with_call_site_ctxt(self, expn_id: ExpnId) -> Span { self.with_ctxt_from_mark(expn_id, Transparency::Transparent) } /// Equivalent of `Span::mixed_site` from the proc macro API, /// except that the location is taken from the `self` span. - pub fn with_mixed_site_ctxt(&self, expn_id: ExpnId) -> Span { + pub fn with_mixed_site_ctxt(self, expn_id: ExpnId) -> Span { self.with_ctxt_from_mark(expn_id, Transparency::SemiTransparent) } diff --git a/compiler/rustc_span/src/span_encoding.rs b/compiler/rustc_span/src/span_encoding.rs index e9120b98aabc6..61e4074a7c80b 100644 --- a/compiler/rustc_span/src/span_encoding.rs +++ b/compiler/rustc_span/src/span_encoding.rs @@ -61,6 +61,15 @@ use rustc_data_structures::fx::FxIndexSet; /// using the callback `SPAN_TRACK` to access the query engine. /// #[derive(Clone, Copy, Eq, PartialEq, Hash)] +// FIXME(@lcnr): Enable this attribute once the bootstrap +// compiler knows of `rustc_pass_by_value`. +// +// Right now, this lint would only trigger when compiling the +// stage 2 compiler, which is fairly annoying as there are +// a lot of places using `&Span` right now. After the next bootstrap bump, +// the lint will already trigger when using stage 1, which is a lot less annoying. +// +// #[cfg_attr(not(bootstrap), rustc_pass_by_value)] pub struct Span { base_or_index: u32, len_or_tag: u16, diff --git a/compiler/rustc_typeck/src/check/method/probe.rs b/compiler/rustc_typeck/src/check/method/probe.rs index 9efaa37633e3e..3815fd1992bf3 100644 --- a/compiler/rustc_typeck/src/check/method/probe.rs +++ b/compiler/rustc_typeck/src/check/method/probe.rs @@ -1904,8 +1904,13 @@ impl<'a, 'tcx> ProbeContext<'a, 'tcx> { .associated_items(def_id) .in_definition_order() .filter(|x| { - let dist = lev_distance(name.as_str(), x.name.as_str()); - x.kind.namespace() == Namespace::ValueNS && dist > 0 && dist <= max_dist + if x.kind.namespace() != Namespace::ValueNS { + return false; + } + match lev_distance(name.as_str(), x.name.as_str(), max_dist) { + Some(d) => d > 0, + None => false, + } }) .copied() .collect() diff --git a/library/core/src/iter/traits/iterator.rs b/library/core/src/iter/traits/iterator.rs index 1d947297463d9..65cadcb6c5a4f 100644 --- a/library/core/src/iter/traits/iterator.rs +++ b/library/core/src/iter/traits/iterator.rs @@ -515,8 +515,44 @@ pub trait Iterator { /// assert_eq!((2, 'o'), zipper[2]); /// ``` /// + /// If both iterators have roughly equivalent syntax, it may me more readable to use [`zip`]: + /// + /// ``` + /// use std::iter::zip; + /// + /// let a = [1, 2, 3]; + /// let b = [2, 3, 4]; + /// + /// let mut zipped = zip( + /// a.into_iter().map(|x| x * 2).skip(1), + /// b.into_iter().map(|x| x * 2).skip(1), + /// ); + /// + /// assert_eq!(zipped.next(), Some((4, 6))); + /// assert_eq!(zipped.next(), Some((6, 8))); + /// assert_eq!(zipped.next(), None); + /// ``` + /// + /// compared to: + /// + /// ``` + /// # let a = [1, 2, 3]; + /// # let b = [2, 3, 4]; + /// # + /// let mut zipped = a + /// .into_iter() + /// .map(|x| x * 2) + /// .skip(1) + /// .zip(b.into_iter().map(|x| x * 2).skip(1)); + /// # + /// # assert_eq!(zipped.next(), Some((4, 6))); + /// # assert_eq!(zipped.next(), Some((6, 8))); + /// # assert_eq!(zipped.next(), None); + /// ``` + /// /// [`enumerate`]: Iterator::enumerate /// [`next`]: Iterator::next + /// [`zip`]: crate::iter::zip #[inline] #[stable(feature = "rust1", since = "1.0.0")] fn zip(self, other: U) -> Zip diff --git a/library/std/src/os/raw/mod.rs b/library/std/src/os/raw/mod.rs index f0b38d2984544..b6d5199341c7d 100644 --- a/library/std/src/os/raw/mod.rs +++ b/library/std/src/os/raw/mod.rs @@ -45,94 +45,13 @@ macro_rules! type_alias { } } -type_alias! { "char.md", c_char = u8, NonZero_c_char = NonZeroU8; -#[doc(cfg(all()))] -#[cfg(any( - all( - target_os = "linux", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "hexagon", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "riscv64", - target_arch = "riscv32" - ) - ), - all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all( - target_os = "freebsd", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "riscv64" - ) - ), - all( - target_os = "netbsd", - any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") - ), - all(target_os = "openbsd", target_arch = "aarch64"), - all( - target_os = "vxworks", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc64", - target_arch = "powerpc" - ) - ), - all(target_os = "fuchsia", target_arch = "aarch64") -))]} -type_alias! { "char.md", c_char = i8, NonZero_c_char = NonZeroI8; -#[doc(cfg(all()))] -#[cfg(not(any( - all( - target_os = "linux", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "hexagon", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "s390x", - target_arch = "riscv64", - target_arch = "riscv32" - ) - ), - all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), - all(target_os = "l4re", target_arch = "x86_64"), - all( - target_os = "freebsd", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc", - target_arch = "powerpc64", - target_arch = "riscv64" - ) - ), - all( - target_os = "netbsd", - any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") - ), - all(target_os = "openbsd", target_arch = "aarch64"), - all( - target_os = "vxworks", - any( - target_arch = "aarch64", - target_arch = "arm", - target_arch = "powerpc64", - target_arch = "powerpc" - ) - ), - all(target_os = "fuchsia", target_arch = "aarch64") -)))]} +type_alias! { "char.md", c_char = c_char_definition::c_char, NonZero_c_char = c_char_definition::NonZero_c_char; +// Make this type alias appear cfg-dependent so that Clippy does not suggest +// replacing `0 as c_char` with `0_i8`/`0_u8`. This #[cfg(all())] can be removed +// after the false positive in https://github.com/rust-lang/rust-clippy/issues/8093 +// is fixed. +#[cfg(all())] +#[doc(cfg(all()))] } type_alias! { "schar.md", c_schar = i8, NonZero_c_schar = NonZeroI8; } type_alias! { "uchar.md", c_uchar = u8, NonZero_c_uchar = NonZeroU8; } type_alias! { "short.md", c_short = i16, NonZero_c_short = NonZeroI16; } @@ -180,3 +99,58 @@ pub type c_ptrdiff_t = isize; /// platforms where this is not the case. #[unstable(feature = "c_size_t", issue = "88345")] pub type c_ssize_t = isize; + +mod c_char_definition { + cfg_if::cfg_if! { + // These are the targets on which c_char is unsigned. + if #[cfg(any( + all( + target_os = "linux", + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "hexagon", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "s390x", + target_arch = "riscv64", + target_arch = "riscv32" + ) + ), + all(target_os = "android", any(target_arch = "aarch64", target_arch = "arm")), + all(target_os = "l4re", target_arch = "x86_64"), + all( + target_os = "freebsd", + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc", + target_arch = "powerpc64", + target_arch = "riscv64" + ) + ), + all( + target_os = "netbsd", + any(target_arch = "aarch64", target_arch = "arm", target_arch = "powerpc") + ), + all(target_os = "openbsd", target_arch = "aarch64"), + all( + target_os = "vxworks", + any( + target_arch = "aarch64", + target_arch = "arm", + target_arch = "powerpc64", + target_arch = "powerpc" + ) + ), + all(target_os = "fuchsia", target_arch = "aarch64") + ))] { + pub type c_char = u8; + pub type NonZero_c_char = core::num::NonZeroU8; + } else { + // On every other target, c_char is signed. + pub type c_char = i8; + pub type NonZero_c_char = core::num::NonZeroI8; + } + } +} diff --git a/src/test/rustdoc-js/generics-multi-trait.js b/src/test/rustdoc-js/generics-multi-trait.js new file mode 100644 index 0000000000000..e7fcea876c85c --- /dev/null +++ b/src/test/rustdoc-js/generics-multi-trait.js @@ -0,0 +1,32 @@ +// exact-check + +const QUERY = [ + 'Result', + 'Zzzzzzzzzzzzzzzzzz', + 'Nonononononononono', +]; + +const EXPECTED = [ + // check one of the generic items + { + 'in_args': [ + { 'path': 'generics_multi_trait', 'name': 'beta' }, + ], + 'returned': [ + { 'path': 'generics_multi_trait', 'name': 'bet' }, + ], + }, + { + 'in_args': [ + { 'path': 'generics_multi_trait', 'name': 'beta' }, + ], + 'returned': [ + { 'path': 'generics_multi_trait', 'name': 'bet' }, + ], + }, + // ignore the name of the generic itself + { + 'in_args': [], + 'returned': [], + }, +]; diff --git a/src/test/rustdoc-js/generics-multi-trait.rs b/src/test/rustdoc-js/generics-multi-trait.rs new file mode 100644 index 0000000000000..e6fd06d254ccd --- /dev/null +++ b/src/test/rustdoc-js/generics-multi-trait.rs @@ -0,0 +1,12 @@ +pub trait SomeTrait {} +pub trait Zzzzzzzzzzzzzzzzzz {} + +pub fn bet() -> Result { + loop {} +} + +pub fn beta( + _param: Result, +) { + loop {} +} diff --git a/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr b/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr index 59732cd84e520..a1056cf85d307 100644 --- a/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr +++ b/src/test/ui-fulldeps/internal-lints/qualified_ty_ty_ctxt.stderr @@ -2,7 +2,7 @@ error: usage of qualified `ty::Ty<'_>` --> $DIR/qualified_ty_ty_ctxt.rs:25:11 | LL | ty_q: ty::Ty<'_>, - | ^^^^^^^^^^ help: try using it unqualified: `Ty<'_>` + | ^^^^^^^^^^ help: try importing it and using it unqualified: `Ty<'_>` | note: the lint level is defined here --> $DIR/qualified_ty_ty_ctxt.rs:4:9 @@ -14,7 +14,7 @@ error: usage of qualified `ty::TyCtxt<'_>` --> $DIR/qualified_ty_ty_ctxt.rs:27:16 | LL | ty_ctxt_q: ty::TyCtxt<'_>, - | ^^^^^^^^^^^^^^ help: try using it unqualified: `TyCtxt<'_>` + | ^^^^^^^^^^^^^^ help: try importing it and using it unqualified: `TyCtxt<'_>` error: aborting due to 2 previous errors