diff --git a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs index a0e53248c9047..1d90b5dbcd10d 100644 --- a/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs +++ b/compiler/rustc_borrowck/src/diagnostics/mutability_errors.rs @@ -1410,9 +1410,20 @@ impl<'infcx, 'tcx> MirBorrowckCtxt<'_, 'infcx, 'tcx> { (span, " mut".to_owned(), true) // If there is already a binding, we modify it to be `mut`. } else if binding_exists { - // Shrink the span to just after the `&` in `&variable`. - let span = span.with_lo(span.lo() + BytePos(1)).shrink_to_lo(); - (span, "mut ".to_owned(), true) + // Replace the sigil with the mutable version. We may be dealing + // with parser recovery here and cannot assume the user actually + // typed `&` or `*const`, so we compute the prefix from the snippet. + let Ok(src) = self.infcx.tcx.sess.source_map().span_to_snippet(span) else { + return; + }; + let (prefix_len, replacement) = if local_decl.ty.is_ref() { + (src.chars().next().map_or(0, char::len_utf8), "&mut ") + } else { + (src.find("const").map_or(1, |i| i + "const".len()), "*mut ") + }; + let ws_len = src[prefix_len..].len() - src[prefix_len..].trim_start().len(); + let span = span.with_hi(span.lo() + BytePos((prefix_len + ws_len) as u32)); + (span, replacement.to_owned(), true) } else { // Otherwise, suggest that the user annotates the binding; We provide the // type of the local. diff --git a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs index 97cfc648b7cb0..bdefacefd20b9 100644 --- a/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs +++ b/compiler/rustc_codegen_ssa/src/mir/naked_asm.rs @@ -8,7 +8,7 @@ use rustc_middle::ty::{Instance, Ty, TyCtxt, TypeVisitableExt}; use rustc_middle::{bug, ty}; use rustc_span::sym; use rustc_target::callconv::{ArgAbi, FnAbi, PassMode}; -use rustc_target::spec::{Arch, BinaryFormat}; +use rustc_target::spec::{Arch, BinaryFormat, Env, Os}; use crate::common; use crate::mir::AsmCodegenMethods; @@ -128,6 +128,8 @@ fn prefix_and_suffix<'tcx>( let is_arm = tcx.sess.target.arch == Arch::Arm; let is_thumb = tcx.sess.unstable_target_features.contains(&sym::thumb_mode); + let function_sections = + tcx.sess.opts.unstable_opts.function_sections.unwrap_or(tcx.sess.target.function_sections); // If we're compiling the compiler-builtins crate, e.g., the equivalent of // compiler-rt, then we want to implicitly compile everything with hidden @@ -218,8 +220,6 @@ fn prefix_and_suffix<'tcx>( let mut end = String::new(); match asm_binary_format { BinaryFormat::Elf => { - let section = link_section.unwrap_or_else(|| format!(".text.{asm_name}")); - let progbits = match is_arm { true => "%progbits", false => "@progbits", @@ -230,7 +230,13 @@ fn prefix_and_suffix<'tcx>( false => "@function", }; - writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap(); + if let Some(section) = &link_section { + writeln!(begin, ".pushsection {section},\"ax\", {progbits}").unwrap(); + } else if function_sections { + writeln!(begin, ".pushsection .text.{asm_name},\"ax\", {progbits}").unwrap(); + } else { + writeln!(begin, ".text").unwrap(); + } writeln!(begin, ".balign {align_bytes}").unwrap(); write_linkage(&mut begin).unwrap(); match visibility { @@ -249,14 +255,22 @@ fn prefix_and_suffix<'tcx>( // pattern match on assembly generated by LLVM. writeln!(end, ".Lfunc_end_{asm_name}:").unwrap(); writeln!(end, ".size {asm_name}, . - {asm_name}").unwrap(); - writeln!(end, ".popsection").unwrap(); + if link_section.is_some() || function_sections { + writeln!(end, ".popsection").unwrap(); + } if !arch_suffix.is_empty() { writeln!(end, "{}", arch_suffix).unwrap(); } } BinaryFormat::MachO => { - let section = link_section.unwrap_or_else(|| "__TEXT,__text".to_string()); - writeln!(begin, ".pushsection {},regular,pure_instructions", section).unwrap(); + // NOTE: LLVM ignores `-Zfunction-sections` on macos. Instead the Mach-O symbol + // subsection splitting feature is used, which can be enabled with the + // `.subsections_via_symbols` global directive. LLVM already enables this directive. + if let Some(section) = &link_section { + writeln!(begin, ".pushsection {section},regular,pure_instructions").unwrap(); + } else { + writeln!(begin, ".section __TEXT,__text,regular,pure_instructions").unwrap(); + } writeln!(begin, ".balign {align_bytes}").unwrap(); write_linkage(&mut begin).unwrap(); match visibility { @@ -267,7 +281,9 @@ fn prefix_and_suffix<'tcx>( writeln!(end).unwrap(); writeln!(end, ".Lfunc_end_{asm_name}:").unwrap(); - writeln!(end, ".popsection").unwrap(); + if link_section.is_some() { + writeln!(end, ".popsection").unwrap(); + } if !arch_suffix.is_empty() { writeln!(end, "{}", arch_suffix).unwrap(); } @@ -278,8 +294,36 @@ fn prefix_and_suffix<'tcx>( writeln!(begin, ".type 32").unwrap(); writeln!(begin, ".endef").unwrap(); - let section = link_section.unwrap_or_else(|| format!(".text.{asm_name}")); - writeln!(begin, ".pushsection {},\"xr\"", section).unwrap(); + if let Some(section) = &link_section { + writeln!(begin, ".section {section},\"xr\"").unwrap() + } else if !function_sections { + // Function sections are enabled by default on MSVC and windows-gnullvm, + // but disabled by default on GNU. + writeln!(begin, ".text").unwrap(); + } else { + // LLVM uses an extension to the section directive to support defining multiple + // sections with the same name and comdat. It adds `unique,` at the end of the + // `.section` directive. We have no way of generating that unique ID here, so don't + // emit it. + // + // See https://llvm.org/docs/Extensions.html#id2. + match &tcx.sess.target.options.env { + Env::Gnu => { + writeln!(begin, ".section .text${asm_name},\"xr\",one_only,{asm_name}") + .unwrap(); + } + Env::Msvc => { + writeln!(begin, ".section .text,\"xr\",one_only,{asm_name}").unwrap(); + } + Env::Unspecified => match &tcx.sess.target.options.os { + Os::Uefi => { + writeln!(begin, ".section .text,\"xr\",one_only,{asm_name}").unwrap(); + } + _ => bug!("unexpected coff target {}", tcx.sess.target.llvm_target), + }, + other => bug!("unexpected coff env {other:?}"), + } + } write_linkage(&mut begin).unwrap(); writeln!(begin, ".balign {align_bytes}").unwrap(); writeln!(begin, "{asm_name}:").unwrap(); diff --git a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs index bd18a215aea70..e2d00238e2d59 100644 --- a/compiler/rustc_mir_build/src/builder/matches/match_pair.rs +++ b/compiler/rustc_mir_build/src/builder/matches/match_pair.rs @@ -12,77 +12,58 @@ use crate::builder::matches::{ FlatPat, MatchPairTree, PatConstKind, PatternExtraData, SliceLenOp, TestableCase, }; -impl<'a, 'tcx> Builder<'a, 'tcx> { - /// Builds and pushes [`MatchPairTree`] subtrees, one for each pattern in - /// `subpatterns`, representing the fields of a [`PatKind::Variant`] or - /// [`PatKind::Leaf`]. - /// - /// Used internally by [`MatchPairTree::for_pattern`]. - fn field_match_pairs( - &mut self, - match_pairs: &mut Vec>, - extra_data: &mut PatternExtraData<'tcx>, - place: PlaceBuilder<'tcx>, - subpatterns: &[FieldPat<'tcx>], - ) { - for fieldpat in subpatterns { - let place = place.clone_project(PlaceElem::Field(fieldpat.field, fieldpat.pattern.ty)); - MatchPairTree::for_pattern(place, &fieldpat.pattern, self, match_pairs, extra_data); - } +/// For an array or slice pattern's subpatterns (prefix/slice/suffix), returns a list +/// of those subpatterns, each paired with a suitably-projected [`PlaceBuilder`]. +fn prefix_slice_suffix<'a, 'tcx>( + place: &PlaceBuilder<'tcx>, + array_len: Option, // Some for array patterns; None for slice patterns + prefix: &'a [Pat<'tcx>], + opt_slice: &'a Option>>, + suffix: &'a [Pat<'tcx>], +) -> Vec<(PlaceBuilder<'tcx>, &'a Pat<'tcx>)> { + let prefix_len = u64::try_from(prefix.len()).unwrap(); + let suffix_len = u64::try_from(suffix.len()).unwrap(); + + let mut output_pairs = + Vec::with_capacity(prefix.len() + usize::from(opt_slice.is_some()) + suffix.len()); + + // For slice patterns with a `..` followed by 0 or more suffix subpatterns, + // the actual slice index of those subpatterns isn't statically known, so + // we have to index them relative to the end of the slice. + // + // For array patterns, all subpatterns are indexed relative to the start. + let (min_length, is_array) = match array_len { + Some(len) => (len, true), + None => (prefix_len + suffix_len, false), + }; + + for (offset, prefix_subpat) in (0u64..).zip(prefix) { + let elem = ProjectionElem::ConstantIndex { offset, min_length, from_end: false }; + let subplace = place.clone_project(elem); + output_pairs.push((subplace, prefix_subpat)); } - /// Builds [`MatchPairTree`] subtrees for the prefix/middle/suffix parts of an - /// array pattern or slice pattern, and adds those trees to `match_pairs`. - /// - /// Used internally by [`MatchPairTree::for_pattern`]. - fn prefix_slice_suffix( - &mut self, - match_pairs: &mut Vec>, - extra_data: &mut PatternExtraData<'tcx>, - place: &PlaceBuilder<'tcx>, - array_len: Option, - prefix: &[Pat<'tcx>], - opt_slice: &Option>>, - suffix: &[Pat<'tcx>], - ) { - let prefix_len = u64::try_from(prefix.len()).unwrap(); - let suffix_len = u64::try_from(suffix.len()).unwrap(); - - // For slice patterns with a `..` followed by 0 or more suffix subpatterns, - // the actual slice index of those subpatterns isn't statically known, so - // we have to index them relative to the end of the slice. - // - // For array patterns, all subpatterns are indexed relative to the start. - let (min_length, is_array) = match array_len { - Some(len) => (len, true), - None => (prefix_len + suffix_len, false), + if let Some(slice_subpat) = opt_slice { + let elem = PlaceElem::Subslice { + from: prefix_len, + to: if is_array { min_length - suffix_len } else { suffix_len }, + from_end: !is_array, }; + let subplace = place.clone_project(elem); + output_pairs.push((subplace, slice_subpat)); + } - for (offset, subpattern) in (0u64..).zip(prefix) { - let elem = ProjectionElem::ConstantIndex { offset, min_length, from_end: false }; - let place = place.clone_project(elem); - MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) - } - - if let Some(subslice_pat) = opt_slice { - let subslice = place.clone_project(PlaceElem::Subslice { - from: prefix_len, - to: if is_array { min_length - suffix_len } else { suffix_len }, - from_end: !is_array, - }); - MatchPairTree::for_pattern(subslice, subslice_pat, self, match_pairs, extra_data); - } - - for (end_offset, subpattern) in (1u64..).zip(suffix.iter().rev()) { - let elem = ProjectionElem::ConstantIndex { - offset: if is_array { min_length - end_offset } else { end_offset }, - min_length, - from_end: !is_array, - }; - let place = place.clone_project(elem); - MatchPairTree::for_pattern(place, subpattern, self, match_pairs, extra_data) - } + for (offset_from_end, suffix_subpat) in (1u64..).zip(suffix.iter().rev()) { + let elem = ProjectionElem::ConstantIndex { + offset: if is_array { min_length - offset_from_end } else { offset_from_end }, + min_length, + from_end: !is_array, + }; + let subplace = place.clone_project(elem); + output_pairs.push((subplace, suffix_subpat)); } + + output_pairs } impl<'tcx> MatchPairTree<'tcx> { @@ -239,15 +220,11 @@ impl<'tcx> MatchPairTree<'tcx> { _ => None, }; if let Some(array_len) = array_len { - cx.prefix_slice_suffix( - &mut subpairs, - extra_data, - &place_builder, - Some(array_len), - prefix, - slice, - suffix, - ); + for (subplace, subpat) in + prefix_slice_suffix(&place_builder, Some(array_len), prefix, slice, suffix) + { + MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data); + } } else { // If the array length couldn't be determined, ignore the // subpatterns and delayed-assert that compilation will fail. @@ -263,15 +240,11 @@ impl<'tcx> MatchPairTree<'tcx> { None } PatKind::Slice { ref prefix, ref slice, ref suffix } => { - cx.prefix_slice_suffix( - &mut subpairs, - extra_data, - &place_builder, - None, - prefix, - slice, - suffix, - ); + for (subplace, subpat) in + prefix_slice_suffix(&place_builder, None, prefix, slice, suffix) + { + MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data); + } if prefix.is_empty() && slice.is_some() && suffix.is_empty() { // This pattern is shaped like `[..]`. It can match a slice @@ -294,7 +267,10 @@ impl<'tcx> MatchPairTree<'tcx> { PatKind::Variant { adt_def, variant_index, args: _, ref subpatterns } => { let downcast_place = place_builder.downcast(adt_def, variant_index); // `(x as Variant)` - cx.field_match_pairs(&mut subpairs, extra_data, downcast_place, subpatterns); + for &FieldPat { field, pattern: ref subpat } in subpatterns { + let subplace = downcast_place.clone_project(PlaceElem::Field(field, subpat.ty)); + MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data); + } // We treat non-exhaustive enums the same independent of the crate they are // defined in, to avoid differences in the operational semantics between crates. @@ -308,7 +284,10 @@ impl<'tcx> MatchPairTree<'tcx> { } PatKind::Leaf { ref subpatterns } => { - cx.field_match_pairs(&mut subpairs, extra_data, place_builder, subpatterns); + for &FieldPat { field, pattern: ref subpat } in subpatterns { + let subplace = place_builder.clone_project(PlaceElem::Field(field, subpat.ty)); + MatchPairTree::for_pattern(subplace, subpat, cx, &mut subpairs, extra_data); + } None } diff --git a/library/core/src/error.rs b/library/core/src/error.rs index 011d6ac4a1c78..0f01c09c8d91c 100644 --- a/library/core/src/error.rs +++ b/library/core/src/error.rs @@ -494,7 +494,7 @@ where /// `Request` supports generic, type-driven access to data. Its use is currently restricted to the /// standard library in cases where trait authors wish to allow trait implementors to share generic /// information across trait boundaries. The motivating and prototypical use case is -/// `core::error::Error` which would otherwise require a method per concrete type (eg. +/// `core::error::Error` which would otherwise require a method per concrete type (e.g. /// `std::backtrace::Backtrace` instance that implementors want to expose to users). /// /// # Data flow @@ -502,29 +502,29 @@ where /// To describe the intended data flow for Request objects, let's consider two conceptual users /// separated by API boundaries: /// -/// * Consumer - the consumer requests objects using a Request instance; eg a crate that offers +/// * Consumer - the consumer requests objects using a Request instance; e.g. a crate that offers /// fancy `Error`/`Result` reporting to users wants to request a Backtrace from a given `dyn Error`. /// -/// * Producer - the producer provides objects when requested via Request; eg. a library with an +/// * Producer - the producer provides objects when requested via Request; e.g. a library with an /// an `Error` implementation that automatically captures backtraces at the time instances are /// created. /// -/// The consumer only needs to know where to submit their request and are expected to handle the +/// The consumer only needs to know where to submit their request and is expected to handle the /// request not being fulfilled by the use of `Option` in the responses offered by the producer. /// /// * A Producer initializes the value of one of its fields of a specific type. (or is otherwise -/// prepared to generate a value requested). eg, `backtrace::Backtrace` or -/// `std::backtrace::Backtrace` +/// prepared to generate a value requested). e.g., `backtrace::Backtrace` or +/// `std::backtrace::Backtrace`. /// * A Consumer requests an object of a specific type (say `std::backtrace::Backtrace`). In the /// case of a `dyn Error` trait object (the Producer), there are functions called `request_ref` and /// `request_value` to simplify obtaining an `Option` for a given type. /// * The Producer, when requested, populates the given Request object which is given as a mutable /// reference. /// * The Consumer extracts a value or reference to the requested type from the `Request` object -/// wrapped in an `Option`; in the case of `dyn Error` the aforementioned `request_ref` and ` -/// request_value` methods mean that `dyn Error` users don't have to deal with the `Request` type at +/// wrapped in an `Option`; in the case of `dyn Error` the aforementioned `request_ref` and +/// `request_value` methods mean that `dyn Error` users don't have to deal with the `Request` type at /// all (but `Error` implementors do). The `None` case of the `Option` suggests only that the -/// Producer cannot currently offer an instance of the requested type, not it can't or never will. +/// Producer cannot currently offer an instance of the requested type, not that it can't or never will. /// /// # Examples /// diff --git a/library/core/src/iter/sources/repeat_n.rs b/library/core/src/iter/sources/repeat_n.rs index c29ab24a08357..4cbaf41852142 100644 --- a/library/core/src/iter/sources/repeat_n.rs +++ b/library/core/src/iter/sources/repeat_n.rs @@ -102,6 +102,15 @@ impl fmt::Debug for RepeatN { } } +/// Creates an empty iterator, like [`repeat_n(value, 0)`][`repeat_n`] +/// but without needing any such value at hand. +#[stable(feature = "iter_repeat_n_default", since = "CURRENT_RUSTC_VERSION")] +impl Default for RepeatN { + fn default() -> Self { + RepeatN { inner: None } + } +} + #[stable(feature = "iter_repeat_n", since = "1.82.0")] impl Iterator for RepeatN { type Item = A; diff --git a/library/core/src/num/uint_macros.rs b/library/core/src/num/uint_macros.rs index b925400e19227..5be1b837798f3 100644 --- a/library/core/src/num/uint_macros.rs +++ b/library/core/src/num/uint_macros.rs @@ -866,7 +866,7 @@ macro_rules! uint_impl { /// # Safety /// /// This results in undefined behavior when - #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX` or `self + rhs < ", stringify!($SelfT), "::MIN`,")] + #[doc = concat!("`self + rhs > ", stringify!($SelfT), "::MAX`,")] /// i.e. when [`checked_add`] would return `None`. /// /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked @@ -1045,7 +1045,7 @@ macro_rules! uint_impl { /// # Safety /// /// This results in undefined behavior when - #[doc = concat!("`self - rhs > ", stringify!($SelfT), "::MAX` or `self - rhs < ", stringify!($SelfT), "::MIN`,")] + #[doc = concat!("`self - rhs < ", stringify!($SelfT), "::MIN`,")] /// i.e. when [`checked_sub`] would return `None`. /// /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked @@ -1254,7 +1254,7 @@ macro_rules! uint_impl { /// # Safety /// /// This results in undefined behavior when - #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX` or `self * rhs < ", stringify!($SelfT), "::MIN`,")] + #[doc = concat!("`self * rhs > ", stringify!($SelfT), "::MAX`,")] /// i.e. when [`checked_mul`] would return `None`. /// /// [`unwrap_unchecked`]: option/enum.Option.html#method.unwrap_unchecked diff --git a/library/coretests/tests/iter/sources.rs b/library/coretests/tests/iter/sources.rs index 420f3088e6ee4..c1df278b54064 100644 --- a/library/coretests/tests/iter/sources.rs +++ b/library/coretests/tests/iter/sources.rs @@ -192,3 +192,19 @@ fn test_repeat_n_soundness() { let _z = y; assert_eq!(0, *x); } + +#[test] +fn test_repeat_n_default() { + #[derive(Clone)] + pub struct PanicOnDrop; + + impl Drop for PanicOnDrop { + fn drop(&mut self) { + unreachable!() + } + } + + // The default is an empty iterator, so there's never any item to drop. + let iter = RepeatN::::default(); + assert_eq!(iter.count(), 0); +} diff --git a/library/std/src/thread/scoped.rs b/library/std/src/thread/scoped.rs index 929f7fdc6dcac..d8e018bde7471 100644 --- a/library/std/src/thread/scoped.rs +++ b/library/std/src/thread/scoped.rs @@ -177,7 +177,7 @@ impl<'scope, 'env> Scope<'scope, 'env> { /// Spawns a new thread within a scope, returning a [`ScopedJoinHandle`] for it. /// /// Unlike non-scoped threads, threads spawned with this function may - /// borrow non-`'static` data from the outside the scope. See [`scope`] for + /// borrow non-`'static` data from outside the scope. See [`scope`] for /// details. /// /// The join handle provides a [`join`] method that can be used to join the spawned diff --git a/src/librustdoc/passes/lint/redundant_explicit_links.rs b/src/librustdoc/passes/lint/redundant_explicit_links.rs index 13bc4c079aa78..8da21f100c6a3 100644 --- a/src/librustdoc/passes/lint/redundant_explicit_links.rs +++ b/src/librustdoc/passes/lint/redundant_explicit_links.rs @@ -90,12 +90,23 @@ fn check_redundant_explicit_link<'md>( .into_offset_iter(); while let Some((event, link_range)) = offset_iter.next() { - if let Event::Start(Tag::Link { link_type, dest_url, .. }) = event { + if let Event::Start(Tag::Link { link_type, dest_url, title, .. }) = event { + if !title.is_empty() { + // Skips if the link specifies a title, e.g. `[Option](Option "title")`, + // in which case the explicit link cannot be removed without also + // removing the title. + continue; + } + let link_data = collect_link_data(&mut offset_iter); - if let Some(resolvable_link) = link_data.resolvable_link.as_ref() - && &link_data.display_link.replace('`', "") != resolvable_link - { + let Some(resolvable_link) = link_data.resolvable_link.as_ref() else { + // collect_link_data didn't return a resolvable_link + // most likely due to the displayed link containing inline markup + continue; + }; + + if &link_data.display_link.replace('`', "") != resolvable_link { // Skips if display link does not match to actual // resolvable link, usually happens if display link // has several segments, e.g. @@ -103,10 +114,7 @@ fn check_redundant_explicit_link<'md>( continue; } - let explicit_link = dest_url.to_string(); - let display_link = link_data.resolvable_link.clone()?; - - if explicit_link.ends_with(&display_link) || display_link.ends_with(&explicit_link) { + if dest_url.ends_with(resolvable_link) || resolvable_link.ends_with(&*dest_url) { match link_type { LinkType::Inline | LinkType::ReferenceUnknown => { check_inline_or_reference_unknown_redundancy( diff --git a/src/tools/run-make-support/src/external_deps/rustc.rs b/src/tools/run-make-support/src/external_deps/rustc.rs index 2fa680a8e2334..e8645e00e1852 100644 --- a/src/tools/run-make-support/src/external_deps/rustc.rs +++ b/src/tools/run-make-support/src/external_deps/rustc.rs @@ -449,6 +449,16 @@ impl Rustc { self.cmd.arg("-Zcodegen-source-order"); self } + + /// Specify `-Z function-sections={yes, no}`. + pub fn function_sections(&mut self, enable: bool) -> &mut Self { + let flag = match enable { + true => "-Zfunction-sections=yes", + false => "-Zfunction-sections=no", + }; + self.cmd.arg(flag); + self + } } /// Query the sysroot path corresponding `rustc --print=sysroot`. diff --git a/tests/assembly-llvm/naked-functions/function-sections.rs b/tests/assembly-llvm/naked-functions/function-sections.rs new file mode 100644 index 0000000000000..751812bd768b2 --- /dev/null +++ b/tests/assembly-llvm/naked-functions/function-sections.rs @@ -0,0 +1,97 @@ +//@ add-minicore +//@ assembly-output: emit-asm +// +//@ revisions: linux-x86-gnu-fs-true linux-x86-gnu-fs-false +//@[linux-x86-gnu-fs-true] compile-flags: --target x86_64-unknown-linux-gnu -Zfunction-sections=true +//@[linux-x86-gnu-fs-true] needs-llvm-components: x86 +//@[linux-x86-gnu-fs-false] compile-flags: --target x86_64-unknown-linux-gnu -Zfunction-sections=false +//@[linux-x86-gnu-fs-false] needs-llvm-components: x86 +// +//@ revisions: macos-aarch64-fs-true macos-aarch64-fs-false +//@[macos-aarch64-fs-true] compile-flags: --target aarch64-apple-darwin -Zfunction-sections=true +//@[macos-aarch64-fs-true] needs-llvm-components: aarch64 +//@[macos-aarch64-fs-false] compile-flags: --target aarch64-apple-darwin -Zfunction-sections=false +//@[macos-aarch64-fs-false] needs-llvm-components: aarch64 +// +//@ revisions: windows-x86-gnu-fs-true windows-x86-gnu-fs-false +//@[windows-x86-gnu-fs-true] compile-flags: --target x86_64-pc-windows-gnu -Zfunction-sections=true +//@[windows-x86-gnu-fs-true] needs-llvm-components: x86 +//@[windows-x86-gnu-fs-false] compile-flags: --target x86_64-pc-windows-gnu -Zfunction-sections=false +//@[windows-x86-gnu-fs-false] needs-llvm-components: x86 +// +//@ revisions: windows-x86-msvc-fs-true windows-x86-msvc-fs-false +//@[windows-x86-msvc-fs-true] compile-flags: --target x86_64-pc-windows-msvc -Zfunction-sections=true +//@[windows-x86-msvc-fs-true] needs-llvm-components: x86 +//@[windows-x86-msvc-fs-false] compile-flags: --target x86_64-pc-windows-msvc -Zfunction-sections=false +//@[windows-x86-msvc-fs-false] needs-llvm-components: x86 +// +//@ revisions: x86-uefi-fs-true x86-uefi-fs-false +//@[x86-uefi-fs-true] compile-flags: --target x86_64-unknown-uefi -Zfunction-sections=true +//@[x86-uefi-fs-true] needs-llvm-components: x86 +//@[x86-uefi-fs-false] compile-flags: --target x86_64-unknown-uefi -Zfunction-sections=false +//@[x86-uefi-fs-false] needs-llvm-components: x86 + +#![crate_type = "lib"] +#![feature(no_core)] +#![no_core] + +// Tests that naked and non-naked functions emit the same directives when (not) using +// -Zfunction-sections. This setting is ignored on macos, off by default on windows gnu, +// and on by default in the remaining revisions tested here. + +extern crate minicore; +use minicore::*; + +#[unsafe(naked)] +#[unsafe(no_mangle)] +extern "C" fn naked_ret() { + // linux-x86-gnu-fs-true: .section .text.naked_ret,"ax",@progbits + // linux-x86-gnu-fs-false: .text + // + // macos-aarch64-fs-true: .section __TEXT,__text,regular,pure_instructions + // macos-aarch64-fs-false: .section __TEXT,__text,regular,pure_instructions + // + // NOTE: the regular function below adds `unique,0` at the end, but we have no way of generating + // the unique ID to use there, so don't emit that part. + // + // windows-x86-gnu-fs-true: .section .text$naked_ret,"xr",one_only,naked_ret + // windows-x86-msvc-fs-true: .section .text,"xr",one_only,naked_ret + // x86-uefi-fs-true: .section .text,"xr",one_only,naked_ret + // + // windows-x86-gnu-fs-false: .text + // windows-x86-msvc-fs-false: .text + // x86-uefi-fs-false: .text + // + // CHECK-LABEL: naked_ret: + naked_asm!("ret") +} + +// Use a different section here so that `regular_ret` has to explicitly specify the section. +#[link_section = cfg_select!( + target_os = "macos" => "__FOO,bar", + _ => ".bar", +)] +#[unsafe(no_mangle)] +extern "C" fn omarker() -> i32 { + // CHECK-LABEL: omarker: + 32 +} + +#[unsafe(no_mangle)] +extern "C" fn regular_ret() { + // linux-x86-gnu-fs-true: .section .text.regular_ret,"ax",@progbits + // linux-x86-gnu-fs-false: .text + // + // macos-aarch64-fs-true: .section __TEXT,__text,regular,pure_instructions + // macos-aarch64-fs-false: .section __TEXT,__text,regular,pure_instructions + // + // windows-x86-gnu-fs-true: .section .text$regular_ret,"xr",one_only,regular_ret,unique,0 + // windows-x86-msvc-fs-true: .section .text,"xr",one_only,regular_ret,unique,0 + // x86-uefi-fs-true: .section .text,"xr",one_only,regular_ret,unique,0 + // + // windows-x86-gnu-fs-false: .text + // windows-x86-msvc-fs-false: .text + // x86-uefi-fs-false: .text + // + // CHECK-LABEL: regular_ret: +} diff --git a/tests/assembly-llvm/naked-functions/link-section-windows.rs b/tests/assembly-llvm/naked-functions/link-section-windows.rs index 5823498973a33..35782a7bf92c4 100644 --- a/tests/assembly-llvm/naked-functions/link-section-windows.rs +++ b/tests/assembly-llvm/naked-functions/link-section-windows.rs @@ -1,4 +1,4 @@ -//@ revisions: windows-x86-gnu windows-x86-msvc +//@ revisions: windows-x86-gnu windows-x86-msvc x86-uefi //@ add-minicore //@ assembly-output: emit-asm // @@ -7,6 +7,9 @@ // //@[windows-x86-msvc] compile-flags: --target x86_64-pc-windows-msvc //@[windows-x86-msvc] needs-llvm-components: x86 +// +//@[x86-uefi] compile-flags: --target x86_64-unknown-uefi +//@[x86-uefi] needs-llvm-components: x86 #![crate_type = "lib"] #![feature(no_core)] diff --git a/tests/codegen-llvm/naked-fn/naked-functions.rs b/tests/codegen-llvm/naked-fn/naked-functions.rs index b5c84ede8f063..a782ab5310e34 100644 --- a/tests/codegen-llvm/naked-fn/naked-functions.rs +++ b/tests/codegen-llvm/naked-fn/naked-functions.rs @@ -1,12 +1,21 @@ +// ignore-tidy-linelength +// //@ add-minicore -//@ revisions: linux win_x86 win_i686 macos thumb +//@ revisions: linux linux_no_function_sections macos thumb +//@ revisions: win_x86_msvc win_x86_gnu win_i686_gnu win_x86_gnu_function_sections // //@[linux] compile-flags: --target x86_64-unknown-linux-gnu //@[linux] needs-llvm-components: x86 -//@[win_x86] compile-flags: --target x86_64-pc-windows-gnu -//@[win_x86] needs-llvm-components: x86 -//@[win_i686] compile-flags: --target i686-pc-windows-gnu -//@[win_i686] needs-llvm-components: x86 +//@[linux_no_function_sections] compile-flags: --target x86_64-unknown-linux-gnu -Zfunction-sections=false +//@[linux_no_function_sections] needs-llvm-components: x86 +//@[win_x86_gnu] compile-flags: --target x86_64-pc-windows-gnu +//@[win_x86_gnu] needs-llvm-components: x86 +//@[win_x86_gnu_function_sections] compile-flags: --target x86_64-pc-windows-gnu -Zfunction-sections +//@[win_x86_gnu_function_sections] needs-llvm-components: x86 +//@[win_x86_msvc] compile-flags: --target x86_64-pc-windows-msvc +//@[win_x86_msvc] needs-llvm-components: x86 +//@[win_i686_gnu] compile-flags: --target i686-pc-windows-gnu +//@[win_i686_gnu] needs-llvm-components: x86 //@[macos] compile-flags: --target aarch64-apple-darwin //@[macos] needs-llvm-components: aarch64 //@[thumb] compile-flags: --target thumbv7em-none-eabi @@ -19,15 +28,22 @@ extern crate minicore; use minicore::*; -// linux,win_x86,win_i686: .intel_syntax +// linux,win_x86_gnu,win_i686_gnu: .intel_syntax // // linux: .pushsection .text.naked_empty,\22ax\22, @progbits -// macos: .pushsection __TEXT,__text,regular,pure_instructions +// linux_no_function_sections: .text +// macos-NOT: .pushsection +// +// win_x86_msvc: .section .text,\22xr\22,one_only,naked_empty +// win_x86_gnu_function_sections: .section .text$naked_empty,\22xr\22,one_only,naked_empty +// win_x86_gnu-NOT: .section +// win_i686_gnu-NOT: .section +// // thumb: .pushsection .text.naked_empty,\22ax\22, %progbits // // linux, macos, thumb: .balign 4 // -// linux,thumb: .globl naked_empty +// linux,win_x86_gnu,thumb: .globl naked_empty // macos: .globl _naked_empty // // CHECK-NOT: .private_extern @@ -35,12 +51,12 @@ use minicore::*; // // linux: .type naked_empty, @function // -// win_x86: .def naked_empty -// win_i686: .def _naked_empty +// win_x86_msvc,win_x86_gnu: .def naked_empty +// win_i686_gnu: .def _naked_empty // -// win_x86,win_i686: .scl 2 -// win_x86,win_i686: .type 32 -// win_x86,win_i686: .endef +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .scl 2 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .type 32 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .endef // // win_x86: .pushsection .text.naked_empty,\22xr\22 // win_i686: .pushsection .text._naked_empty,\22xr\22 @@ -56,10 +72,11 @@ use minicore::*; // // CHECK-LABEL: naked_empty: // -// linux,macos,win_x86,win_x86: ret +// linux,macos,win_x86_msvc,win_x86_gnu,win_i686_gnu: ret // thumb: bx lr // -// linux,macos,thumb: .popsection +// linux,windows,win_x86_msvc,thumb: .popsection +// win_x86_gnu-NOT,win_i686_gnu-NOT: .popsection // // thumb: .thumb // @@ -78,15 +95,22 @@ pub extern "C" fn naked_empty() { } } -// linux,win_x86,win_i686: .intel_syntax +// linux,win_x86_gnu,win_i686_gnu,win_x86_msvc: .intel_syntax // // linux: .pushsection .text.naked_with_args_and_return,\22ax\22, @progbits -// macos: .pushsection __TEXT,__text,regular,pure_instructions +// linux_no_function_sections: .text +// macos-NOT: .pushsection +// +// win_x86_msvc: .section .text,\22xr\22,one_only,naked_with_args_and_return +// win_x86_gnu_function_sections: .section .text$naked_with_args_and_return,\22xr\22,one_only,naked_with_args_and_return +// win_x86_gnu-NOT: .section +// win_i686_gnu-NOT: .section +// // thumb: .pushsection .text.naked_with_args_and_return,\22ax\22, %progbits // // linux, macos, thumb: .balign 4 // -// linux,thumb: .globl naked_with_args_and_return +// linux,win_x86_gnu,win_x86_msvc,win_i686_gnu,thumb: .globl naked_with_args_and_return // macos: .globl _naked_with_args_and_return // // CHECK-NOT: .private_extern @@ -94,12 +118,12 @@ pub extern "C" fn naked_empty() { // // linux: .type naked_with_args_and_return, @function // -// win_x86: .def naked_with_args_and_return -// win_i686: .def _naked_with_args_and_return +// win_x86_msvc,win_x86_gnu: .def naked_with_args_and_return +// win_i686_gnu: .def _naked_with_args_and_return // -// win_x86,win_i686: .scl 2 -// win_x86,win_i686: .type 32 -// win_x86,win_i686: .endef +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .scl 2 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .type 32 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .endef // // win_x86: .pushsection .text.naked_with_args_and_return,\22xr\22 // win_i686: .pushsection .text._naked_with_args_and_return,\22xr\22 @@ -115,14 +139,15 @@ pub extern "C" fn naked_empty() { // // CHECK-LABEL: naked_with_args_and_return: // -// linux, win_x86,win_i686: lea rax, [rdi + rsi] +// linux,win_x86_msvc,win_x86_gnu,win_i686_gnu: lea rax, [rdi + rsi] // macos: add x0, x0, x1 // thumb: adds r0, r0, r1 // -// linux,macos,win_x86,win_i686: ret +// linux,macos,win_x86_msvc,win_x86_gnu,win_i686_gnu: ret // thumb: bx lr // -// linux,macos,thumb: .popsection +// linux,windows,win_x86_msvc,thumb: .popsection +// win_x86_gnu-NOT,win_i686_gnu-NOT: .popsection // // thumb: .thumb // @@ -144,9 +169,10 @@ pub extern "C" fn naked_with_args_and_return(a: isize, b: isize) -> isize { } } -// linux: .pushsection .text.some_different_name,\22ax\22, @progbits +// linux,linux_no_function_sections: .pushsection .text.some_different_name,\22ax\22, @progbits // macos: .pushsection .text.some_different_name,regular,pure_instructions -// win_x86,win_i686: .pushsection .text.some_different_name,\22xr\22 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .section .text.some_different_name,\22xr\22 +// win_x86_gnu_function_sections: .section .text.some_different_name,\22xr\22 // thumb: .pushsection .text.some_different_name,\22ax\22, %progbits // CHECK-LABEL: test_link_section: #[no_mangle] @@ -163,15 +189,15 @@ pub extern "C" fn test_link_section() { } } -// win_x86: .def fastcall_cc -// win_i686: .def @fastcall_cc@4 +// win_x86_msvc,win_x86_gnu: .def fastcall_cc +// win_i686_gnu: .def @fastcall_cc@4 // -// win_x86,win_i686: .scl 2 -// win_x86,win_i686: .type 32 -// win_x86,win_i686: .endef +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .scl 2 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .type 32 +// win_x86_msvc,win_x86_gnu,win_i686_gnu: .endef // -// win_x86-LABEL: fastcall_cc: -// win_i686-LABEL: @fastcall_cc@4: +// win_x86_msvc-LABEL,win_x86_gnu-LABEL: fastcall_cc: +// win_i686_gnu-LABEL: @fastcall_cc@4: #[cfg(target_os = "windows")] #[no_mangle] #[unsafe(naked)] diff --git a/tests/crashes/139089.rs b/tests/crashes/139089.rs deleted file mode 100644 index 3326aa6ad9846..0000000000000 --- a/tests/crashes/139089.rs +++ /dev/null @@ -1,2 +0,0 @@ -//@ known-bug: #139089 -pub fn foo3(x: &Vec) { x.push(0); } diff --git a/tests/run-make/naked-dead-code-elimination/main.rs b/tests/run-make/naked-dead-code-elimination/main.rs new file mode 100644 index 0000000000000..5df2691e5b443 --- /dev/null +++ b/tests/run-make/naked-dead-code-elimination/main.rs @@ -0,0 +1,48 @@ +#![feature(cfg_target_object_format)] +use std::arch::naked_asm; + +#[unsafe(naked)] +#[unsafe(no_mangle)] +extern "C" fn used() { + naked_asm!("ret") +} + +#[unsafe(no_mangle)] +extern "C" fn used_clothed() -> i32 { + 41 +} + +pub fn main() { + std::hint::black_box(used()); + std::hint::black_box(used_clothed()); +} + +#[unsafe(no_mangle)] +extern "C" fn unused_clothed() -> i32 { + 42 +} + +#[unsafe(naked)] +#[unsafe(no_mangle)] +extern "C" fn unused() { + naked_asm!("ret") +} + +#[unsafe(naked)] +#[unsafe(link_section = cfg_select!( + target_object_format = "mach-o" => "__TEXT,foobar", + _ => ".foobar", +))] +#[unsafe(no_mangle)] +extern "C" fn unused_link_section() { + naked_asm!("ret") +} + +#[unsafe(link_section = cfg_select!( + target_object_format = "mach-o" => "__TEXT,baz", + _ => ".baz", +))] +#[unsafe(no_mangle)] +extern "C" fn unused_link_section_clothed() -> i32 { + 43 +} diff --git a/tests/run-make/naked-dead-code-elimination/rmake.rs b/tests/run-make/naked-dead-code-elimination/rmake.rs new file mode 100644 index 0000000000000..1be22de367c99 --- /dev/null +++ b/tests/run-make/naked-dead-code-elimination/rmake.rs @@ -0,0 +1,39 @@ +//@ ignore-cross-compile +//@ needs-asm-support + +use run_make_support::symbols::object_contains_any_symbol; +use run_make_support::{bin_name, rustc}; + +fn main() { + let bin = bin_name("main"); + + rustc().input("main.rs").opt().function_sections(false).run(); + + // Check that the naked symbol is eliminated when the "clothed" one is. + + assert_eq!( + object_contains_any_symbol(&bin, &["unused_clothed"]), + object_contains_any_symbol(&bin, &["unused"]) + ); + + assert_eq!( + object_contains_any_symbol(&bin, &["unused_link_section_clothed"]), + object_contains_any_symbol(&bin, &["unused_link_section"]) + ); + + // --- + + rustc().input("main.rs").opt().function_sections(true).run(); + + // Check that the naked symbol is eliminated when the "clothed" one is. + + assert_eq!( + object_contains_any_symbol(&bin, &["unused_clothed"]), + object_contains_any_symbol(&bin, &["unused"]) + ); + + assert_eq!( + object_contains_any_symbol(&bin, &["unused_link_section_clothed"]), + object_contains_any_symbol(&bin, &["unused_link_section"]) + ); +} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links-some-skipped.fixed b/tests/rustdoc-ui/lints/redundant_explicit_links-some-skipped.fixed new file mode 100644 index 0000000000000..75e2398e64c5a --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links-some-skipped.fixed @@ -0,0 +1,17 @@ +//@ run-rustfix + +// There was a logic error in `redundant_explicit_links` that caused the lint +// to skip all remaining links once it skipped a link containing inline markups. +// This test asserts that the lint continues after skipping such links. + +#![deny(rustdoc::redundant_explicit_links)] + +/// [Option] +///~^ ERROR redundant explicit link target +/// +/// [**u8**](u8) +/// This link should not lint. +/// +/// [Result] +///~^ ERROR redundant explicit link target +pub fn func() {} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links-some-skipped.rs b/tests/rustdoc-ui/lints/redundant_explicit_links-some-skipped.rs new file mode 100644 index 0000000000000..0c39ad8f18013 --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links-some-skipped.rs @@ -0,0 +1,17 @@ +//@ run-rustfix + +// There was a logic error in `redundant_explicit_links` that caused the lint +// to skip all remaining links once it skipped a link containing inline markups. +// This test asserts that the lint continues after skipping such links. + +#![deny(rustdoc::redundant_explicit_links)] + +/// [Option][Option] +///~^ ERROR redundant explicit link target +/// +/// [**u8**](u8) +/// This link should not lint. +/// +/// [Result][Result] +///~^ ERROR redundant explicit link target +pub fn func() {} diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links-some-skipped.stderr b/tests/rustdoc-ui/lints/redundant_explicit_links-some-skipped.stderr new file mode 100644 index 0000000000000..61f4ee584da8b --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links-some-skipped.stderr @@ -0,0 +1,39 @@ +error: redundant explicit link target + --> $DIR/redundant_explicit_links-some-skipped.rs:9:14 + | +LL | /// [Option][Option] + | ------ ^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +note: the lint level is defined here + --> $DIR/redundant_explicit_links-some-skipped.rs:7:9 + | +LL | #![deny(rustdoc::redundant_explicit_links)] + | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ +help: remove explicit link target + | +LL - /// [Option][Option] +LL + /// [Option] + | + +error: redundant explicit link target + --> $DIR/redundant_explicit_links-some-skipped.rs:15:14 + | +LL | /// [Result][Result] + | ------ ^^^^^^ explicit target is redundant + | | + | because label contains path that resolves to same destination + | + = note: when a link's destination is not specified, + the label is used to resolve intra-doc links +help: remove explicit link target + | +LL - /// [Result][Result] +LL + /// [Result] + | + +error: aborting due to 2 previous errors + diff --git a/tests/rustdoc-ui/lints/redundant_explicit_links-with-title.rs b/tests/rustdoc-ui/lints/redundant_explicit_links-with-title.rs new file mode 100644 index 0000000000000..01b84563ce556 --- /dev/null +++ b/tests/rustdoc-ui/lints/redundant_explicit_links-with-title.rs @@ -0,0 +1,15 @@ +//@ check-pass + +#![deny(rustdoc::redundant_explicit_links)] + +/// [drop](drop "This function is not magic") +/// +/// This link should not lint, because it specifies a link title, and it is +/// not possible to remove the explicit link without also removing the title. +/// +/// [Vec][vec] +/// +/// [vec]: std::vec::Vec "A contiguous growable array type" +/// +/// This also applies to reference-style links. +pub fn func() {} diff --git a/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr index 62d456c5510a2..84c689d81c9ce 100644 --- a/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr +++ b/tests/ui/borrowck/borrowck-assign-to-andmut-in-aliasable-loc.stderr @@ -17,7 +17,7 @@ LL | *s.pointer += 1; | help: consider changing this to be a mutable reference | -LL | fn c(s: &mut &mut S) { +LL | fn c(s: &mut &mut S) { | +++ error: aborting due to 2 previous errors diff --git a/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr index 7e516fe89b40c..11607159eb013 100644 --- a/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr +++ b/tests/ui/borrowck/borrowck-borrow-mut-base-ptr-in-aliasable-loc.stderr @@ -27,7 +27,7 @@ LL | let x: &mut isize = &mut **t0; | help: consider changing this to be a mutable reference | -LL | fn foo4(t0: &mut &mut isize) { +LL | fn foo4(t0: &mut &mut isize) { | +++ error: aborting due to 3 previous errors diff --git a/tests/ui/borrowck/mutability-errors.stderr b/tests/ui/borrowck/mutability-errors.stderr index 18d8e6eb1a6e7..34adf33a99c2d 100644 --- a/tests/ui/borrowck/mutability-errors.stderr +++ b/tests/ui/borrowck/mutability-errors.stderr @@ -74,8 +74,9 @@ LL | *x = (1,); | help: consider changing this to be a mutable pointer | -LL | unsafe fn named_ptr(x: *mut const (i32,)) { - | +++ +LL - unsafe fn named_ptr(x: *const (i32,)) { +LL + unsafe fn named_ptr(x: *mut (i32,)) { + | error[E0594]: cannot assign to `x.0`, which is behind a `*const` pointer --> $DIR/mutability-errors.rs:24:5 @@ -85,8 +86,9 @@ LL | (*x).0 = 1; | help: consider changing this to be a mutable pointer | -LL | unsafe fn named_ptr(x: *mut const (i32,)) { - | +++ +LL - unsafe fn named_ptr(x: *const (i32,)) { +LL + unsafe fn named_ptr(x: *mut (i32,)) { + | error[E0596]: cannot borrow `*x` as mutable, as it is behind a `*const` pointer --> $DIR/mutability-errors.rs:25:5 @@ -96,8 +98,9 @@ LL | &mut *x; | help: consider changing this to be a mutable pointer | -LL | unsafe fn named_ptr(x: *mut const (i32,)) { - | +++ +LL - unsafe fn named_ptr(x: *const (i32,)) { +LL + unsafe fn named_ptr(x: *mut (i32,)) { + | error[E0596]: cannot borrow `x.0` as mutable, as it is behind a `*const` pointer --> $DIR/mutability-errors.rs:26:5 @@ -107,8 +110,9 @@ LL | &mut (*x).0; | help: consider changing this to be a mutable pointer | -LL | unsafe fn named_ptr(x: *mut const (i32,)) { - | +++ +LL - unsafe fn named_ptr(x: *const (i32,)) { +LL + unsafe fn named_ptr(x: *mut (i32,)) { + | error[E0594]: cannot assign to data in a `*const` pointer --> $DIR/mutability-errors.rs:30:5 diff --git a/tests/ui/span/mutability-suggestion-fullwidth-ampersand.rs b/tests/ui/span/mutability-suggestion-fullwidth-ampersand.rs new file mode 100644 index 0000000000000..a9bdd381307e7 --- /dev/null +++ b/tests/ui/span/mutability-suggestion-fullwidth-ampersand.rs @@ -0,0 +1,9 @@ +// Regression test for https://github.com/rust-lang/rust/issues/139089 + +fn foo(x: &Vec) { + //~^ ERROR unknown start of token + x.push(0); + //~^ ERROR cannot borrow `*x` as mutable +} + +fn main() {} diff --git a/tests/ui/span/mutability-suggestion-fullwidth-ampersand.stderr b/tests/ui/span/mutability-suggestion-fullwidth-ampersand.stderr new file mode 100644 index 0000000000000..e6712f5da9a83 --- /dev/null +++ b/tests/ui/span/mutability-suggestion-fullwidth-ampersand.stderr @@ -0,0 +1,27 @@ +error: unknown start of token: \u{ff06} + --> $DIR/mutability-suggestion-fullwidth-ampersand.rs:3:11 + | +LL | fn foo(x: &Vec) { + | ^^ + | +help: Unicode character '&' (Fullwidth Ampersand) looks like '&' (Ampersand), but it is not + | +LL - fn foo(x: &Vec) { +LL + fn foo(x: &Vec) { + | + +error[E0596]: cannot borrow `*x` as mutable, as it is behind a `&` reference + --> $DIR/mutability-suggestion-fullwidth-ampersand.rs:5:5 + | +LL | x.push(0); + | ^ `x` is a `&` reference, so it cannot be borrowed as mutable + | +help: consider changing this to be a mutable reference + | +LL - fn foo(x: &Vec) { +LL + fn foo(x: &mut Vec) { + | + +error: aborting due to 2 previous errors + +For more information about this error, try `rustc --explain E0596`.